zoukankan      html  css  js  c++  java
  • OpenCV2马拉松第14圈——边缘检測(Sobel,prewitt,roberts)

    收入囊中
    • 差分在边缘检測的角色
    • Sobel算子
    • OpenCV sobel函数
    • OpenCV Scharr函数
    • prewitt算子
    • Roberts算子

    葵花宝典
    差分在边缘检測究竟有什么用呢?先看以下的图片
    作为人,我们能够非常easy发现图中红圈有边界,边界处肯定是非常明显,变化陡峭的,在数学中,什么能够表示变化的快慢,自然就是导数,微分了。

    想像有例如以下的一维图片。
    红圈处变化最陡峭,再看导数图


    红圈在最高值,也就是导数能够非常好表示边缘,由于变化非常剧烈


    图像中的Sobel算子
    1. 是离散差分算子.
    2. 结合了高斯滤波.

    I是原始图像:

    1. 我们计算水平和竖直方向的梯度:

      1. 水平方向: Gx是我们Kernel size为3的水平sober算子,与I作卷积

        G_{x} = egin{bmatrix}-1 & 0 & +1  \-2 & 0 & +2  \-1 & 0 & +1end{bmatrix} * I

      2. 竖直方向:Gy是我们Kernel size为3的水平sober算子,与I作卷积

        G_{y} = egin{bmatrix}-1 & -2 & -1  \0 & 0 & 0  \+1 & +2 & +1end{bmatrix} * I

    2. 对每一个点,再计算以下的值,得到方向无关梯度

      G = sqrt{ G_{x}^{2} + G_{y}^{2} }

      有时候也能够这样计算:

      G = |G_{x}| + |G_{y}|





    初识API
    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 –
      output image depth; the following combinations of src.depth() and ddepth are supported:
      • 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

      when ddepth=-1, the destination image will have the same depth as the source; in the case of 8-bit input images it will result in truncated derivatives.这里要特别注意了,我们的depth不能为-1,由于我们的输入是uchar8类型的,而算出来的值可能>255也可能 <0 ,都会被截断,CV_16S是推荐的

    • xorder – order of the derivative x.
    • yorder – order of the derivative y.
    • ksize – sobel核大小,必须为1, 3, 5, or 7.
    • scale – 扩大系数
    • delta – 附加系数
    • borderType – 边界类型

    计算的时候,利用了可分离的滤波进行加速(Ksize=1的时候,用了1*3和 3*1的算子,无法加速)

    当Ksize = 3,Sobel採用的算子会不准确,因此还有特殊的值ksize = CV_SCHARR(-1) 相当于使用 3	imes3 Scharr filter 比 3	imes3Sobel算子能获得更准确的结果. Scharr 算子例如以下

    vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}



    C++: void Scharr(InputArray src, OutputArray dst, int ddepth, int dx, int dy, double scale=1, double delta=0, int borderType=BORDER_DEFAULT )
     
    • src – input image.
    • dst – output image of the same size and the same number of channels as src.
    • ddepth – output image depth (see Sobel() for the list of supported combination of src.depth() and ddepth).
    • dx – order of the derivative x.
    • dy – order of the derivative y.
    • scale – optional scale factor for the computed derivative values; by default, no scaling is applied (see getDerivKernels() for details).
    • delta – optional delta value that is added to the results prior to storing them in dst.
    • borderType – pixel extrapolation method (see borderInterpolate() for details).

    The function computes the first x- or y- spatial image derivative using the Scharr operator. The call

    	exttt{Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType)}

    is equivalent to

    	exttt{Sobel(src, dst, ddepth, dx, dy, CV\_SCHARR, scale, delta, borderType)} .

    用法一样~~


    荷枪实弹
    #include "opencv2/imgproc/imgproc.hpp"
    #include "opencv2/highgui/highgui.hpp"
    #include <stdlib.h>
    #include <stdio.h>
    
    using namespace cv;
    
    int main( int, char** argv )
    {
    
      Mat src, src_gray;
      Mat grad;
      const char* window_name = "Sobel Demo - Simple Edge Detector";
      
      //由于以Sobel方式求完导数后会有负值,还有会大于255的值而你建的Sobel的图像是 CV_8U,也就是8位无符号数,所以Sobel建立的图像位数不够,要16位有符号的,也就是 CV_16S
      int ddepth = CV_16S;
      src = imread( argv[1] );
      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 );
    
      // 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);
      Sobel( src_gray, grad_x, ddepth, 1, 0, 3);
      convertScaleAbs( grad_x, abs_grad_x );
    
      // Gradient Y
      //Scharr( src_gray, grad_y, ddepth, 0, 1);
      Sobel( src_gray, grad_y, ddepth, 0, 1, 3);
      convertScaleAbs( grad_y, abs_grad_y );
    
      // Total Gradient (approximate)
      addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
    
      imshow( window_name, grad );
    
      waitKey(0);
    
      return 0;
    }

    效果图:




    举一反三
    该算子与Sobel算子类似,仅仅是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检測图像边缘。

    Robert算子是一种梯度算子,它用交叉的差分表示梯度,是一种利用局部差分算子寻找边缘的算子,对具有陡峭的低噪声的图像效果最好:

    以下我们来用prewitt算子作边缘检測,还记得我们曾经在http://blog.csdn.net/abcd1992719g/article/details/24625805用过的自己定义滤波不,以下我们又要用上了。
    #include "opencv2/highgui/highgui.hpp"  
    #include "opencv2/imgproc/imgproc.hpp"  
    using namespace cv;   
    
    int main( int, char** argv )  
    {  
    	Mat src,gray,Kernelx,Kernely;
    	 
        src = imread( argv[1] );  
        cvtColor( src, gray, CV_RGB2GRAY );
        namedWindow("srcImage", 1);  
        namedWindow("dstImage", 1);  
      
        Kernelx = (Mat_<double>(3,3) << 1, 1, 1, 0, 0, 0, -1, -1, -1);  
        Kernely = (Mat_<double>(3,3) << -1, 0, 1, -1, 0, 1, -1, 0, 1); 
        
        Mat grad_x, grad_y;
      	Mat abs_grad_x, abs_grad_y, grad;
      
        filter2D(gray, grad_x, CV_16S , Kernelx, Point(-1,-1));  
        filter2D(gray, grad_y, CV_16S , Kernely, Point(-1,-1));
        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 ); 
        imshow("dstImage", grad);  
     
        waitKey();  
        return 0;  
    } 

    效果图:






    计算机视觉讨论群162501053
    转载请注明:http://blog.csdn.net/abcd1992719g


  • 相关阅读:
    Linux 修改 root密码
    python实现 CI/CD(jenkins+gitlab)
    redis集群
    土木工程材料0732
    C语言程序设计【1032】
    汽车文化【1196】
    应用写作0045
    思想道德修养与法律基础[1053]
    英语【0002】
    社区管理【0272】
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/3819172.html
Copyright © 2011-2022 走看看