zoukankan      html  css  js  c++  java
  • Sobel 边缘检测算子

    转自:http://blog.csdn.net/xiaqunfeng123/article/details/17302003

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

        图像边缘,相素值会发生显著的变化了。表示这一改变的一个方法是使用 导数 。 梯度值的大变预示着图像中内容的显著变化。用更加形象的图像来解释,假设我们有一张一维图形。下图2中灰度值的”跃升”表示边缘的存在,图3中使用一阶微分求导我们可以更加清晰的看到边缘”跃升”的存在。

    图1、lena.jpg 

     图2、像素一维图形

    图3、一阶导数

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

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

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

    在图像的每一点,结合以上两个结果求出近似 梯度 ,如图4c:

    图4a

    图4b

    图4c

    因为Sobel算子只是求取了导数的近似值,当内核大小为3时,以上Sobel内核可能产生比较明显的误差。为解决这一问题,OpenCV提供了 Scharr 函数,但该函数仅作用于大小为3的内核,该函数的运算与Sobel函数一样快,但结果却更加精确。

    两种实现版本:

    C 版本:

    cvSobel ( const cvArr* src, CvArr* dst, int xorder, int yorder, int aperture_size =3 )

    src,  dst 分别是源图像和目标图像,xorder ,yorder – 分别为x,y方向导数运算参数,可取0,1,2  。aperture_size是方形滤波器的宽,是小于7的奇数。

    具体见《Learning OpenCV》那本书,P.170页

    下面是代码,比较简单:

    #include <highgui.h>  
    #include <cv.h>  
      
    using namespace cv;  
    using namespace std;  
      
    int main(int argc, char ** argv)  
    {  
        IplImage* src, *dstx,*dsty,*dst;  
      
        src = cvLoadImage( "car.png",0 );  
        dst = cvCreateImage( cvGetSize( src ), IPL_DEPTH_16S, 1 );  
        dstx = cvCreateImage( cvGetSize( src ), IPL_DEPTH_16S, 1 );  
        dsty = cvCreateImage( cvGetSize( src ), IPL_DEPTH_16S, 1 );  
      
        cvNamedWindow( "src" );  
        cvNamedWindow( "sobel" );  
      
        cvShowImage( "src", src );  
      
        cvSobel( src, dstx, 1, 0, 7 );  //sobel  
        cvSobel( src, dsty, 0, 1, 7 );  
        cvAddWeighted(dstx,0.5,dsty,0.5,0,dst);  
      
        cvShowImage( "sobel", dst );  
      
        cvWaitKey(0);  
        cvReleaseImage( &src );  
        cvReleaseImage( &dst );  
      
        return 0;  
    }  

    效果图:

    C++版本:

    先来看一下C++下 Sobel 的定义

    C++:   void 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_8Uddepth = -1/CV_16S/CV_32F/CV_64F

    src.depth() = CV_16U/CV_16Sddepth = -1/CV_32F/CV_64F

    src.depth() = CV_32Fddepth = -1/CV_32F/CV_64F

    src.depth() = CV_64Fddepth = -1/CV_64F

    当 ddepth为-1时, 输出图像将和输入图像有相同的深度。输入8位图像则会截取顶端的导数。

    xorder – x方向导数运算参数。yorder – y方向导数运算参数。

    ksize – Sobel内核的大小,可以是:1,3,5,7。  注意:只可以是小于7 的奇数

    scale – 可选的缩放导数的比例常数。delta – 可选的增量常数被叠加到导数中。borderType – 用于判断图像边界的模式。

    下面是程序:

    #include "opencv2/imgproc/imgproc.hpp"  
    #include "opencv2/highgui/highgui.hpp"  
    #include <stdlib.h>  
    #include <stdio.h>  
      
    using namespace cv;  
    using namespace std;  
      
    int main( int argc, char** argv )  
    {  
        Mat src, src_gray;  
        Mat grad;  
        char* window_name = "求解梯度";  
        int scale = 1;  
        int delta = 0;  
        int ddepth = CV_16S;  
      
        src = imread( "car.png" );  
        if( !src.data )  
        {   
            return -1;   
        }  
        //高斯模糊  
        GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );  
        //转成灰度图  
        cvtColor( src, src_gray,CV_RGB2GRAY );  
      
        namedWindow( window_name, CV_WINDOW_AUTOSIZE );  
      
        Mat grad_x, grad_y;  
        Mat abs_grad_x, abs_grad_y;  
        //x方向梯度计算  
        Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );  
        convertScaleAbs( grad_x, abs_grad_x );  
        //y方向梯度计算  
        Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );  
        convertScaleAbs( grad_y, abs_grad_y );  
        //加权和  
        addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );  
      
        imshow( window_name, grad );  
      
        waitKey();  
        return 0;  
    }  

    如果要用Scharr滤波器的话,把Sobel那行代码替换掉就好了:

    Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );  
    Scharr( src_gray, grad_x, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );  

    效果图:

    参考资料:http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html

    转载请注明出处:http://blog.csdn.net/xiaqunfeng123

  • 相关阅读:
    kubernetes-handbook 阅读笔记
    kubernetes-notes--阅读笔记
    SpringInAction4笔记——复习
    spring源码解析——2容器的基本实现(第2版笔记)
    把node加入master节点时,日志内容分析
    初始化master节点时,日志内容分析
    Mac OS用minikube安装单节点kubernetes
    Mac OS用vmvare安装多节点kubernetes
    FatMouse's Speed 基础DP
    FatMouse and Cheese 动态化搜索
  • 原文地址:https://www.cnblogs.com/sevenyuan/p/7874344.html
Copyright © 2011-2022 走看看