我是靠谱客的博主 落后水杯,最近开发中收集的这篇文章主要介绍【OpenCV图像处理】1.17 Sobel算子,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • Sobel算子
      • 相关理论
      • 2. 代码 & 效果

Sobel算子

相关理论

  • 卷积应用-图像边缘提取

    • 边缘是什么?是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
    • 如何捕捉/提取边缘 – 对图像求它的一阶导数
      d e l t a = f ( x ) – f ( x − 1 ) delta = f(x) – f(x-1) delta=f(x)f(x1), delta越大,说明像素在X方向变化越大,边缘信号越强,
    • 如果已经忘记求导如何计算,不要担心,用Sobel算子就好!卷积操作!边缘提取 。
  • Sobel算子

    • 是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度
    • Soble算子功能集合高斯平滑和微分求导
    • 又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像。拉普拉斯算子是二阶微分算子
  • Sobel算子

    • 水平梯度

      • G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ I mathrm{G}_{mathrm{x}}=left[begin{array}{ccc}{-1} & {0} & {+1} \ {-2} & {0} & {+2} \ {-1} & {0} & {+1}end{array}right] * mathrm{I} Gx=121000+1+2+1I
    • 垂直梯度

      • G y = [ − 1 − 2 − 1 0 0 0 + 1 + 2 + 1 ] ∗ I mathrm{G}_{mathrm{y}}=left[begin{array}{ccc}{-1} & {-2} & {-1} \ {0} & {0} & {0} \ {+1} & {+2} & {+1}end{array}right] * mathrm{I} Gy=10+120+210+1I
    • 最终图像梯度,2种计算方法:

      • G = G x 2 + G y 2 mathbf{G}=sqrt{mathbf{G}_{mathbf{x}}^{2}+mathbf{G}_{mathbf{y}}^{2}} G=Gx2+Gy2
      • G = ∣ G x ∣ + ∣ G y ∣ mathbf{G}=left|mathbf{G}_{mathbf{x}}right|+left|mathbf{G}_{mathbf{y}}right| G=Gx+Gy
  • Sobel算子

    • 求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:
      • G x = [ − 3 0 + 3 − 10 0 + 10 − 3 0 + 3 ] G_{x}=left[begin{array}{ccc}{-3} & {0} & {+3} \ {-10} & {0} & {+10} \ {-3} & {0} & {+3}end{array}right] Gx=3103000+3+10+3
      • G y = [ − 3 − 10 − 3 0 0 0 + 3 + 10 + 3 ] G_{y}=left[begin{array}{ccc}{-3} & {-10} & {-3} \ {0} & {0} & {0} \ {+3} & {+10} & {+3}end{array}right] Gy=30+3100+1030+3
  • API说明 - Sobel

    cv::Sobel (
    InputArray Src // 输入图像
    OutputArray dst// 输出图像,大小与输入图像一致
    int depth // 输出图像深度. 
    Int dx.  // X方向,几阶导数
    int dy // Y方向,几阶导数. 
    int ksize, // SOBEL算子kernel大小,必须是1、3、5、7、
    double scale  = 1
    double delta = 0
    int borderType = BORDER_DEFAULT
    )
    

其中input_depthoutput_depth的取值

  • Sobel类似API - Scharr

    • 对边缘得到了更大的加强,一点点扰动是不用担心的,但Sobel算子一点扰动是不行的
    cv::Scharr (
    InputArray Src // 输入图像
    OutputArray dst// 输出图像,大小与输入图像一致
    int depth // 输出图像深度. 
    Int dx.  // X方向,几阶导数
    int dy // Y方向,几阶导数. 
    double scale  = 1
    double delta = 0
    int borderType = BORDER_DEFAULT
    )
    
  • 使用Sobel算子,计算步骤

    • 高斯平滑处理
    • 转灰度
    • 求梯度 X和Y
    • 整幅图像
  • 其他需要使用到的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

2. 代码 & 效果

完整代码:

#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>

using namespace std;
using namespace cv;

#ifndef P17
#define P17 16
#endif

int main() {
    std::string path = "../fei.JPG";
    cv::Mat img = cv::imread(path, 5);

    string str_input = "input image";
    string str_output = "output image";

    if(img.empty())
    {
        std::cout << "open file failed" << std::endl;
        return -1;
    }

#if P18     //Sobel算子
    Mat gray;
    GaussianBlur(img, img,Size(3,3),0,0);
    cvtColor(img,gray, COLOR_BGR2GRAY);

    Mat xgrad, ygrad;
    Sobel(gray,xgrad,CV_16S, 1,0,3);
    Sobel(gray,ygrad,CV_16S, 0,1,3);
    convertScaleAbs(xgrad,xgrad);
    convertScaleAbs(ygrad,ygrad);

    namedWindow("xgrad",WINDOW_AUTOSIZE);
    namedWindow("ygrad",WINDOW_AUTOSIZE);
    imshow("xgrad",xgrad);
    imshow("ygrad",ygrad);

    Mat xygrad = Mat(xgrad.size(), xgrad.type());
    Mat xygrad_cv = Mat(xgrad.size(), xgrad.type());

    printf("type: %dn",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);
        }
    }

    // 求得整体的Sobel,和上面的作用一样。效果比上面的差一些
    addWeighted(xgrad,0.5, ygrad, 05, 0, xygrad_cv);
    namedWindow("final", WINDOW_AUTOSIZE);
    imshow("final",xygrad);
    namedWindow("final by cv", WINDOW_AUTOSIZE);
    imshow("final by cv",xygrad_cv);
#endif

    cv::waitKey(0);
    cv::destroyAllWindows();
    return 0;
}

上面的for循环是逐像素计算梯度,以此求得梯度。addWeighted和两个for循环的作用一样,效果比addWeighted好一些。
效果图:

在这里插入图片描述

addWeighted和两个for循环的效果对比,这里是一样的计算原理,为啥不一样有待研究
在这里插入图片描述

改进版本Scharr函数代码,使用Scharr替换Sobel即可,其余部分一致:

    Scharr(gray,xgrad,CV_16S,1,0);
    Scharr(gray,ygrad,CV_16S,0,1);

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

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

最后

以上就是落后水杯为你收集整理的【OpenCV图像处理】1.17 Sobel算子的全部内容,希望文章能够帮你解决【OpenCV图像处理】1.17 Sobel算子所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部