opencv计算图像梯度:Sobel、Scharr、Laplacian、Canny详解

opencv计算图像梯度:Sobel、Scharr、Laplacian、Canny详解

1.边界填充

函数:

void cv::copyMakeBorder	(InputArray 	src,
                         OutputArray 	dst,
                         int 	top,  
                         int 	bottom,
                         int 	left,
                         int 	right,
                         int 	borderType, //填充类型
                         const Scalar & value = Scalar() //填充颜色 
)		
Python:
cv.copyMakeBorder(	src, top, bottom, left, right, borderType[, dst[, value]]	) ->	dst

填充类型:

  • BORDER_CONSTANT:用固定值填充图像
  • BORDER_REPLICATE:原始边界最边缘的行或列被复制到额外的边界。

使用如下:

RNG rng(12345);
int top, bottom, left, right;
int borderType = BORDER_CONSTANT;
// Initialize arguments for the filter
top = (int) (0.05*src.rows); bottom = top;
left = (int) (0.05*src.cols); right = left;

Scalar value( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );

在这里插入图片描述

2. Sobel算子

边缘检测原理如下图所示:
在这里插入图片描述
数学原理:
在这里插入图片描述
函数:

void cv::Sobel	(InputArray 	src,
                 OutputArray 	dst,
                 int 	ddepth,  
                 int 	dx,    //x方向
                 int 	dy,    //y方向
                 int 	ksize = 3, //核大小
                 double 	scale = 1,
                 double 	delta = 0,
                 int 	borderType = BORDER_DEFAULT 
)		
Python:
cv.Sobel(	src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]	) ->	dst

变换函数:

void cv::convertScaleAbs( InputArray 	src,
                          OutputArray 	dst,
                          double 	alpha = 1,  //对比度
                          double 	beta = 0  //亮度
)		
Python:
cv.convertScaleAbs(	src[, dst[, alpha[, beta]]]	) ->	dst

变换原理:
在这里插入图片描述
求梯度:

cvtColor(src, src_gray, COLOR_BGR2GRAY);
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
Sobel(src_gray, grad_x, ddepth, 1, 0, ksize, scale, delta, BORDER_DEFAULT);
Sobel(src_gray, grad_y, ddepth, 0, 1, ksize, scale, delta, BORDER_DEFAULT);
// converting back to CV_8U
convertScaleAbs(grad_x, abs_grad_x);
convertScaleAbs(grad_y, abs_grad_y);
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad);

在这里插入图片描述

3. Scharr算子

函数接口:

void cv::Scharr	(InputArray 	src,
                 OutputArray 	dst,
                 int 	ddepth,
                 int 	dx,
                 int 	dy,
                 double 	scale = 1,
                 double 	delta = 0,
                 int 	borderType = BORDER_DEFAULT 
)		
Python:
cv.Scharr(	src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]	) ->	dst

在这里插入图片描述
当核的大小为3时,上面所示的Sobel核可能产生明显的不准确性(毕竟,Sobel只是导数的近似值)。OpenCV通过使用Scharr()函数解决了大小为3的内核的不准确性问题。这与标准Sobel函数一样快,但更准确。它实现了以下内核:
在这里插入图片描述
求梯度时,与Sobel算子实现代码相同,下边给出边缘检测应用:

Mat dx,dy;
Scharr(blurImage,dx,CV_16S,1,0);
Scharr(blurImage,dy,CV_16S,0,1);
Canny( dx,dy, edge2, edgeThreshScharr, edgeThreshScharr*3 );
cedge = Scalar::all(0);
image.copyTo(cedge, edge2);

4. Laplacian算子

图形化数学原理:
在这里插入图片描述

void cv::Laplacian(	InputArray 	src,
                    OutputArray 	dst,
                    int 	ddepth,
                    int 	ksize = 1,
                    double 	scale = 1,
                    double 	delta = 0,
                    int 	borderType = BORDER_DEFAULT 
)		
Python:
cv.Laplacian(	src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]]	) ->	dst

在这里插入图片描述
求梯度实现:

cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to grayscale
Mat abs_dst;
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
// converting back to CV_8U
convertScaleAbs( dst, abs_dst );

在这里插入图片描述

5.Canny

边缘检测算法步骤:

  • 先经过高斯平滑,目的是去噪声

  • 寻找图像强度梯度

  • 非极大值抑制
    上一步算出来的边缘可能比较粗糙,假设边缘是一条很细的线的话,上面处理完的结果你可以理解为得到一条比较粗的线条,所谓非极大值抑制,就是要在局部像素点中找到变换最剧烈的一个点,这样就得到了更细的边缘.

  • 双阈值检测和连接边缘

void Canny(cv::InputArray src, 
            cv::OutputArray dst,
            double threshold1,  //梯度小于minVal的像素点弃用,不视为边缘
            double threshold2,  //梯度大于maxVal的像素点保留,视为边缘
            int aperture_size=3   
          );

详细参考:
https://blog.csdn.net/Vermont_/article/details/108471205
https://blog.csdn.net/xddwz/article/details/111585648

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
 
using namespace std;
using namespace cv;
int main() {
    Mat srcImage, grayImage;
    srcImage = imread("/Users/dwz/Desktop/cpp/1.jpg");
    Mat srcImage1 = srcImage.clone();
    cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
    Mat dstImage, edge;
 
    blur(grayImage, grayImage, Size(3,3));
    Canny(grayImage, edge, 150, 100, 3);
 
    dstImage.create(srcImage1.size(), srcImage1.type());
    dstImage = Scalar::all(0);
    srcImage1.copyTo(dstImage, edge);
    imwrite("canny.jpg", dstImage);
 
    return 0;
}

6.总结

  • 研究这个算子是想将其放在特征匹配前,通过对原始图像求出梯度,分析梯度图像的灰度信息特征来进行特征提取,发现加入梯度求解后算法耗时增加,二维卷积确实引进了不少耗时,竟然要高于同样尺寸大小的模板匹配
  • 梯度算子对于提取图像中的关键特征具有重要作用,是作为轮廓提取的重要步骤
  • 通常情况下,二维算子的效果要强于一维算子效果。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值