博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
OpenCV2马拉松第14圈——边缘检測(Sobel,prewitt,roberts)
阅读量:4570 次
发布时间:2019-06-08

本文共 4537 字,大约阅读时间需要 15 分钟。

收入囊中
  • 差分在边缘检測的角色
  • Sobel算子
  • OpenCV sobel函数
  • OpenCV Scharr函数
  • prewitt算子
  • Roberts算子
葵花宝典
差分在边缘检測究竟有什么用呢?先看以下的图片
作为人,我们能够非常easy发现图中红圈有边界,边界处肯定是非常明显,变化陡峭的,在数学中,什么能够表示变化的快慢,自然就是导数,微分了。
想像有例如以下的一维图片。
红圈处变化最陡峭,再看导数图
红圈在最高值,也就是导数能够非常好表示边缘,由于变化非常剧烈
图像中的Sobel算子
  1. 是离散差分算子.
  2. 结合了高斯滤波.

I是原始图像:

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

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

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

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

      G_{y} = \begin{bmatrix}-1 & -2 & -1  \\0 & 0 & 0  \\+1 & +2 & +1\end{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, int
borderType=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\times3 Scharr filter 比 3\times3Sobel算子能获得更准确的结果. 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  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  for details).
  • delta – optional delta value that is added to the results prior to storing them in dst.
  • borderType – pixel extrapolation method (see  for details).

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

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

is equivalent to

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

用法一样~~
荷枪实弹
#include "opencv2/imgproc/imgproc.hpp"#include "opencv2/highgui/highgui.hpp"#include 
#include
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算子作边缘检測,还记得我们曾经在用过的自己定义滤波不,以下我们又要用上了。
#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_
(3,3) << 1, 1, 1, 0, 0, 0, -1, -1, -1); Kernely = (Mat_
(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

转载于:https://www.cnblogs.com/mengfanrong/p/3819172.html

你可能感兴趣的文章
站立会议05(冲刺2)
查看>>
Java学习(final、static关键词)
查看>>
怎样判断网址是否被微信封 微信域名检测接口的实现
查看>>
解一元二次方程程序
查看>>
Homebrew macOS缺失包管理器
查看>>
WIN32 窗口类封装 框架实现部分
查看>>
操作系统
查看>>
记录 一次深夜救火:datanode.data.dir
查看>>
Apache 使用 .htaccess 文件配置全站 301 跳转代码
查看>>
微信小程序 获取OpenId
查看>>
IDEA快捷操作
查看>>
android 的touch event分析
查看>>
转:C#进阶系列——WebApi 跨域问题解决方案:CORS
查看>>
实参和形参
查看>>
利用GPGPU计算大规模群落仿真行为
查看>>
BZOJ 3211: 花神游历各国【线段树区间开方问题】
查看>>
C语言sprintf和sscanf函数用法
查看>>
javascript 基础
查看>>
WAV文件格式
查看>>
WPF stringformat设置
查看>>