Sobel算子

Sobel算子和梯度计算

一、目的与原理

(1)目的:Sobel算子主要用于边缘检测,对噪声平滑抑制。

(2)原理:图像梯度用于边缘检测。边缘是像素值发生跃迁的地方,是图像的显著特征之一。图像中有灰度值的变化就会有梯度,从而产生边缘,在边缘处,具有变化的强弱及方向。图像上可以使用一阶差分来计算相邻像素之间的变化率,我们利用卷积和特定的算子来计算相邻像素的变化率。sobel算子可以计算相邻三个点之间的变化率。它们用于一阶算子的边缘检测,利用像素点上下、左右相邻点的灰度差求取边缘。计算水平梯度,检测垂直边缘 ,计算垂直梯度,检测水平边缘,最后通过将水平边缘图和垂直边缘图相加可近似得总边缘图。

 

原信号与求导数之间的变化关系:

 

下图中灰度值的“跃升”表示边缘的存在:

 

使用一阶微分求导我们可以更加清晰的看到边缘“跃升”的存在(这里显示为局部极大值):

 

 

  

梯度理论知识:

图像是离散函数,在某点的梯度可以用向前差商、向后差商或者中心差商获得。这里采用中心差商可以获取图像某点的导数值。

由于除法会导致低阶的重要字节丢失, 所以我们把向量乘与一个数将分母忽略掉,分子写成一维卷积的形式相当于[1,0,-1]。Sobel模板之所以能够较好的抑制噪声效果,

有平滑的效果的原因是将中间行的系数加大,即Sobel卷积模板一般如下:  

 

 

计算图像梯度值的步骤:

1. 分别与图像进行卷积

 

 

 

 

 

2. 把得到的值写在一起得到图像梯度向量

 

 

 

 

 

 

其中梯度方向为:

 

 

 

 

 

梯度幅度:

 

 

 

 

 

两个结果求出近似 梯度:

 

 

 

 

也可以用下面更简单公式代替:

 

 

 

 

 

二、步骤

方法一:

(1)将图片转化为灰度图

(2)通过x方向的卷积核计算出X方向的灰度值

(3)通过y方向的卷积核计算出y方向的灰度值

(4)x方向的y方向的灰度图叠加成为整体边缘

 

方法二:

(1)将图片转化为灰度图

(2)根据卷积核权重对像素点的灰度值卷积

(3) 对卷积结果平方根处理

(4) 对平方根结果进行截断处理

(5) 将最终结果赋值到输出图像中

(6) 显示图像

 

 

三、伪代码

方法一:

输入:原图src

输出:结果图dst

void SobelXY(Mat src, Mat &dst)

{

         If(判断src是否为灰度图)

                   不是灰度图则转为灰度图

        

         根据卷积核权重对像素点的灰度值卷积,然后相乘(平方)

         对上一步的平方结果开根号

         对上一步开根号处理结果进行截断处理

         将结果赋值到输出图像

}

 

 

方法二:

输入:原图src

输出:X方向的结果图dst

void SobelX (Mat src, Mat &dst)

{

         If(判断src是否为灰度图)

                   不是灰度图则转为灰度图

        

         根据卷积核权重对像素点的灰度值卷积

         截断处理

         将结果赋值到输出图像,得到X方向的结果图

}

 

 

输入:原图src

输出:Y方向的结果图dst

void SobelY (Mat src, Mat &dst)

{

         If(判断src是否为灰度图)

                   不是灰度图则转为灰度图

        

         根据卷积核权重对像素点的灰度值卷积

         截断处理

         将结果赋值到输出图像,得到Y方向的结果图

}

 

四、特点

优点:索贝尔算子不但产生较好的边缘检测效果,而且对噪声具有平滑抑制作用

缺点:得到的边缘较粗,且可能出现伪边缘。

 

五、源码

void SobelXY(Mat src, Mat &dst)

{

    int temp=0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

            temp = sqrt((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*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]));

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = temp;

 

        }

 

    }

}

 

 

 

 

void SobelX(Mat src, Mat &dst)

{

    int temp=0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

 

            temp =

                +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];

 

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = abs(temp);

        }

    }

}

 

 

void SobelY(Mat src,Mat& dst)

{

    int temp = 0;

    for (int i = 1; i < src.rows - 1; i++)

    {

        for (int j = 1; j < src.cols - 1; j++)

        {

                temp

                = 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];

 

            if (temp < 0)

                temp = 0;

            if (temp > 255)

                temp = 255;

            dst.data[i*dst.step + j] = abs(temp);

        }

    }

}

 

 

 

 

 

 

六、结果图

X+Y方式结果图:

 

 

 

 

平方开根号方式结果图:

 

 

posted @ 2021-05-08 09:12  will-z  阅读(2992)  评论(0编辑  收藏  举报