OpenCV学习笔记10 OpenCV图像处理模块ImgProc Module. Image Processing(三)

3.8 Sobel导数- Sobel Derivatives


对图像中的像素值随着位置的变化求导,导数大(梯度值变化大)的地方可能是边缘线。因此求图像中边缘线的方法之一是可以定位梯度值大于邻域(或者大于某一阈值)的像素。
Sobel算子:Sobel算子是一个离散微分算子(discrete differentiation operator)。用于计算图像中描述灰度变化的函数的近似梯度。Sobel算子结合了高斯平滑和微分求导。
利用Sobel算子计算梯度变化。设原图像为 I 。
 -1 0 +1-1  -2  -1
举例:检测水平变化: Gx = [-2 0 +2 ] * I检测垂直变化:Gy =      [ 0   0   0   ] * I 
 -1 0 +1+1 +2 +1
然后求出近似梯度 G = sqrt(Gx * Gx + Gy * Gy),或者 G = |Gx| + |Gy| 。
代码:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 

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;

  /// 读入图像
  src = imread( argv[1] );

  if( !src.data )
  { return -1; }
  /// 先对图像进行高斯平滑降噪,核大小为3
  GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );

  /// 转换为灰度图
  cvtColor( src, src_gray, CV_RGB2GRAY );

  /// 创建显示窗口
  namedWindow( window_name, CV_WINDOW_AUTOSIZE );

  /// 创建 grad_x 和 grad_y 矩阵
  Mat grad_x, grad_y;
  Mat abs_grad_x, abs_grad_y;

  /// 求 X方向梯度
  //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT ); // 注1
  Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
  convertScaleAbs( grad_x, abs_grad_x );// 尺度化,求绝对值,图像矩阵数据转换成 CV_8U 数据类型

  /// 求Y方向梯度
  //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT ); // 注2
  Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
  convertScaleAbs( grad_y, abs_grad_y );// 尺度化,求绝对值,图像矩阵数据转换成 CV_8U 数据类型

  /// 合并梯度(近似) 2.4节 图像混合
  addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );

  imshow( window_name, grad );

  waitKey(0);

  return 0;
  }
Sobel函数中,grad_xgrad_y都是输出图像,ddepth是输出图像的深度,设定为CV_16S防止外溢。
x_ordery_order分别是x,y方向上求导的阶数,在代码中对应1,0(X方向求导)和0,1(Y方向求导)。
ksize是索伯核的大小,必须是1,3,5,7中的一个,代码中为3。
scaledeltaBORDER_DEFAULT都使用默认值。
注1和注2: 当核的大小为3时,Sobel算子可能产生比较明显的误差。OpenCV提供了Scharr函数,该函数仅作用于大小为3的核,运算速度同 Sobel函数,结果更加精确。


3.9 Laplace 算子 - Laplace Operator


2阶导数可以用来检测边缘点(边缘点二阶导数为0),Laplacian 函数实现Laplacian算子,由于使用了图像梯度,内部调用了Sobel。
边缘检测的过程同上一节,加载图像 -> 高斯平滑降噪 -> 转换为灰度图 -> 对灰度图使用Laplacian算子 -> 将输出图像的深度转换为 CV_8U -> 显示结果。
其中 Laplacian 函数的用法:
Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );

src_gray:输入图像。
dst :输出图像。
ddepth:输出图像的深度。
kernel_size:内部调用的Sobel算子的核大小。
scaledeltaBORDER_DEFAULT:使用默认值。


3.10 Canny 边缘检测 - Canny Edge Detector


最优边缘检测的三个主要评价标准:
1. 低错误率:标识出尽可能多的实际边缘,同时尽可能的减少噪声产生的误报。
2. 高定位性:标识出的边缘要与图像中的实际边缘尽可能接近。
3. 最小响应:图像中的边缘只能标识一次。
Canny算子被很多人认为是边缘检测的 最优算子。

步骤:
1. 消除噪声:高斯平滑。
2. 计算梯度幅度和方向:类似Sobel算子。
3. 非极大值抑制:保留候选边缘,排除非边缘像素。
4. 滞后阈值(Hysteresis):Canny算子使用两个阈值(低阈值和高阈值)。
如果某一像素梯度大于高阈值,该像素被保留为边缘像素。
如果某一像素梯度小于低阈值,该像素被排除。
如果某一像素梯度在两个阈值之间,只有它和大于高阈值的边缘像素相连时才被保留为边缘像素。
Canny算子推荐 高阈值:低阈值 的比例为 2:1和3:1之间。
 Canny( image, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
image:输入图像。
detected_edges:输出边缘图像。
lowThreshold:低阈值。
lowThreshold*ratio:高阈值。
kernel_size:核大小。

你可能感兴趣的:(opencv)