zoukankan      html  css  js  c++  java
  • Sobel Derivatives

    https://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html

    OpenCV 2.4 C++ 边缘梯度计算 --- sobel 使用说明

    Sobel算子

    Sobel 算子是一个离散微分算子 (discrete differentiation operator)。 它结合了高斯平滑和微分求导,用来计算图像灰度函数的近似梯度。

    一.基础知识介绍

    [1]图像的边缘

    图像的边缘从数学上是如何表示的呢?

    图像的边缘上,邻近的像素值应当显著地改变了。而在数学上,导数是表示改变快慢的一种方法,一个函数在某一点的导数描述了这个函数在这一点附近的变化率。

    梯度可谓是多元函数的偏导,表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。。

    用更加形象的图像来解释,假设我们有一张一维图形。下图中灰度值的“跃升”表示边缘的存在:

        

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

      

    由此我们可以得出:边缘可以通过定位梯度值大于邻域的相素的方法找到。

    [2]卷积

    卷积可以近似地表示求导运算。

    那么卷积是什么呢?

    卷积是在每一个图像块与某个算子(核)之间进行的运算。

    核呢?

    核就是一个固定大小的数值数组。该数组带有一个锚点 ,一般位于数组中央。

     可是这怎么运算啊?

    假如你想得到图像的某个特定位置的卷积值,可用下列方法计算:

    1. 将核的锚点放在该特定位置的像素上,同时,核内的其他值与该像素邻域的各像素重合;
    2. 将核内各值与相应像素值相乘,并将乘积相加;
    3. 将所得结果放到与锚点对应的像素上;
    4. 对图像所有像素重复上述过程。

    用公式表示上述过程如下:

        

    在图像边缘的卷积怎么办呢?

    计算卷积前,OpenCV通过复制源图像的边界创建虚拟像素,这样边缘的地方也有足够像素计算卷积了。

    二.Sobel的卷积实现

    Sobel是采用卷积的计算方法实现的。假设被作用的图像为I ,在两个方向上求导:

    水平变化求导:将 I 与一个奇数大小的内核 G_{x} 进行卷积。比如,当内核大小为3时, G_{x} 的计算结果为图1

    垂直变化求导:将 I 与一个奇数大小的内核 G_{y} 进行卷积。比如,当内核大小为3时, G_{y} 的计算结果为图2

    在图像的每一点,结合以上两个结果求出近似梯度大小 ,如图3

    计算梯度方向,如图4   (如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗)

                  图1                                  图2                                    图3                         图4

    三.Code

    先来看一下C++下 Sobel 的定义
    
    cv:Sobel(  InputArray src ,  OutputArray dst,  int ddepth,  int dx,  int dy,  int ksize=3,   
    
                 double scale=1,double delta=0,intborderType=BORDER_DEFAULT )
    
    各参数的意义如下:
    
    src – 输入图像。
    dst – 输出图像,与输入图像同样大小,拥有同样个数的通道。 ddepth –输出图片深度;下面是输入图像支持深度和输出图像支持深度的关系: src.depth()
    = CV_8U, ddepth = -1/CV_16S/CV_32F/CV_64F src.depth() = CV_16U/CV_16S, ddepth = -1/CV_32F/CV_64F src.depth() = CV_32F, ddepth = -1/CV_32F/CV_64F src.depth() = CV_64F, ddepth = -1/CV_64F 当 ddepth为-1时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数。 xorder – x方向导数运算参数。
    yorder – y方向导数运算参数。 ksize – Sobel内核的大小,可以是:
    1357。 注意:只可以是小于7 的奇数 scale – 可选的缩放导数的比例常数。
    delta – 可选的增量常数被叠加到导数中。
    borderType – 用于判断图像边界的模式。
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace cv;
    
    /** @function main */
    int main( int argc, char** argv )
    {
    
      Mat src, src_gray;
      Mat grad;
      char* window_name = "Sobel Demo - Simple Edge Detector";
      int scale = 1;
      int delta = 0;
      int ddepth = CV_16S;
    
      int c;
    
      /// Load an image
      src = imread( argv[1] );
    
      if( !src.data )
      { return -1; }
     
    ///高斯模糊---apply a GaussianBlur to our image to reduce the noise ( kernel size = 3 ) GaussianBlur( src, src, Size(
    3,3), 0, 0, BORDER_DEFAULT ); /// Convert it to gray cvtColor( src, src_gray, CV_BGR2GRAY ); /// Create window namedWindow( window_name, CV_WINDOW_AUTOSIZE );
    ///calculate the “derivatives” in x and y directions
    /// Generate grad_x and grad_y Mat grad_x, grad_y; Mat abs_grad_x, abs_grad_y; /// Gradient X //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); convertScaleAbs( grad_x, abs_grad_x ); //convert our partial results back to CV_8U /// Gradient Y //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); convertScaleAbs( grad_y, abs_grad_y ); /// Total Gradient (approximate近似)---we try to approximate the gradient by adding both directional gradients
    (note that this is not an exact calculation at all! but it is good for our purposes).
    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); imshow( window_name, grad ); waitKey(0); return 0; }
  • 相关阅读:
    AutoMapper,对象映射的简单使用
    Angular 4.0从入门到实战
    IE报错:The given path's format is not supported
    原生js中slice()方法和splice()区别
    使用jquery插件ajaxfileupload一次上传多个文件,示例
    C#路径中获取文件全路径、目录、扩展名、文件名称
    NET二进制图片存储与读取的常见方法,iTextSharp添加图片生成PDF文件
    Type.GetType()反射另外项目中的类时返回null的解决方法
    C#中对于Enum类型的遍历
    读取word到二进制,再转成word
  • 原文地址:https://www.cnblogs.com/Jessica-jie/p/8531177.html
Copyright © 2011-2022 走看看