Sobel 导数

目标

本文档尝试解答如下问题:

  • 如何使用OpenCV函数 Sobel 对图像求导。
  • 如何使用OpenCV函数 Scharr 更准确地计算  核的导数。

原理

Note

以下内容来自于Bradski和Kaehler的大作: Learning OpenCV .

  1. 上面两节我们已经学习了卷积操作。一个最重要的卷积运算就是导数的计算(或者近似计算).

  2. 为什么对图像进行求导是重要的呢? 假设我们需要检测图像中的 边缘 ,如下图:

    你可以看到在 边缘 ,相素值显著的 改变 了。表示这一 改变 的一个方法是使用 导数 。 梯度值的大变预示着图像中内容的显著变化。

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

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

  5. 从上例中我们可以推论检测边缘可以通过定位梯度值大于邻域的相素的方法找到(或者推广到大于一个阀值).

  6. 更加详细的解释,请参考Bradski 和 Kaehler的 Learning OpenCV 。

Sobel算子

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

计算

假设被作用图像为 :

  1. 在两个方向求导:

    1. 水平变化: 将  与一个奇数大小的内核  进行卷积。比如,当内核大小为3时, 的计算结果为:

    2. 垂直变化: 将:math:I 与一个奇数大小的内核  进行卷积。比如,当内核大小为3时,  的计算结果为:

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

    有时也用下面更简单公式代替:

Note

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

关于( Scharr )的更多信息请参考OpenCV文档。在下面的示例代码中,你会发现在 Sobel 函数调用的上面有被注释掉的 Scharr 函数调用。 反注释Scharr调用 (当然也要相应的注释掉Sobel调用),看看该函数是如何工作的。

源码

  1. 本程序做什么?

    • 使用 Sobel算子 产生的输出图像上,检测到的亮起的 边缘 相素散布在更暗的背景中。
  2. 下面是本教程的源码,你也可以从 here 下载
#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; /// 装载图像
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 ); /// 创建 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 );
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x ); /// 求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 ); /// 合并梯度(近似)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad ); imshow( window_name, grad ); waitKey(0); return 0;
}

解释

  1. 首先申明变量:

    Mat src, src_gray;
    Mat grad;
    char* window_name = "Sobel Demo - Simple Edge Detector";
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
  2. 装载原图像 src:

    src = imread( argv[1] );
    
    if( !src.data )
    { return -1; }
  3. 第一步对原图像使用 GaussianBlur 降噪 ( 内核大小 = 3 )

    GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
    
  4. 将降噪后的图像转换为灰度图:

    cvtColor( src, src_gray, CV_RGB2GRAY );
    
  5. 第二步,在 x 和 y 方向分别”求导“。 为此,我们使用函数 Sobel :

    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 );
    /// 求 Y方向梯度
    Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );

    该函数接受了以下参数:

    • src_gray: 在本例中为输入图像,元素类型 CV_8U
    • grad_x/grad_y: 输出图像.
    • ddepth: 输出图像的深度,设定为 CV_16S 避免外溢。
    • x_orderx 方向求导的阶数。
    • y_ordery 方向求导的阶数。
    • scaledelta 和 BORDER_DEFAULT: 使用默认值

    注意为了在 x 方向求导我们使用:  , . 采用同样方法在 y 方向求导。

  6. 将中间结果转换到 CV_8U:

    convertScaleAbs( grad_x, abs_grad_x );
    convertScaleAbs( grad_y, abs_grad_y );
  7. 将两个方向的梯度相加来求取近似 梯度 (注意这里没有准确的计算,但是对我们来讲已经足够了)。

    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
    
  8. 最后,显示结果:

    imshow( window_name, grad );
    

结果

  1. 这里是将Sobel算子作用于 lena.jpg 的结果:

Sobel导数的更多相关文章

  1. 2.7 Sobel导数

    OpenCV函数 Sobel(src_gray,grad_x/grad_y,ddepth,x_order,y_order,scale,delta,BORDER_DEFAULT ) Scharr( ) ...

  2. OpenCV Sobel 导数

    #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/highgui/highgui.hpp" #i ...

  3. opencv-学习笔记(6)图像梯度Sobel以及canny边缘检测

    opencv-学习笔记(6)图像梯度Sobel以及canny边缘检测 这章讲了 sobel算子 scharr算子 Laplacion拉普拉斯算子 图像深度问题 Canny检测 图像梯度 sobel算子 ...

  4. 2.opencv图像处理常用操作

    图像的平滑处理 平滑,也称 模糊, 平滑处理时需要用到一个滤波器 .滤波器想象成一个包含加权系数的窗口,这个加权系数也叫做核或者模版. // 图像平滑处理分而学之.cpp : 定义控制台应用程序的入口 ...

  5. 【OpenCV新手教程第14】OpenCVHough变换:霍夫变换线,霍夫变换圆汇编

    本系列文章由@浅墨_毛星云 出品.转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/26977557 作者:毛星云(浅墨) ...

  6. SciPy模块应用

    1.图像模糊  图像的高斯模糊是非常经典的图像卷积例子.本质上,图像模糊就是将(灰度)图像I 和一个高斯核进行卷积操作:,其中是标准差为σ的二维高斯核.高斯模糊通常是其他图像处理操作的一部分,比如图像 ...

  7. [OpenCV-Python] OpenCV 中的图像处理 部分 IV (二)

    部分 IVOpenCV 中的图像处理 OpenCV-Python 中文教程(搬运)目录 16 图像平滑 目标 • 学习使用不同的低通滤波器对图像进行模糊 • 使用自定义的滤波器对图像进行卷积(2D 卷 ...

  8. [OpenCV-Python] OpenCV 中机器学习 部分 VIII

    部分 VIII机器学习 OpenCV-Python 中文教程(搬运)目录 46 K 近邻(k-Nearest Neighbour ) 46.1 理解 K 近邻目标 • 本节我们要理解 k 近邻(kNN ...

  9. OpenCV常用库函数[典]

    一.core 模块 1.Mat - 基本图像容器 Mat 是一个类,由两个数据部分组成:矩阵头(包含矩阵尺寸,存储方法,存储地址等信息)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同矩阵可以是 ...

随机推荐

  1. [转载]Axure RP 7.0下载地址及安装说明

    Axure RP是产品经理必备的原型制作工具,因为很多同学是新手,在这里整理一下axure7.0的下载.安装和汉化流程,希望能够帮到大家. Axure RP是美国Axure Software Solu ...

  2. df 命令

    linux中df命令的功能是用来检查linux服务器的文件系统的磁盘空间占用情况.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 1.命令格式: df [选项] [文件] 2.命 ...

  3. EJB是什么?(节选)

    近期的项目中使用了EJB.当时就仅仅知道怎么用,没有深入的去理解.当完毕这个项目之后.再回想项目中使用的技术.框架以及工具的时候,突然感觉对EJB这个概念非常是模糊,于是上网搜一些资料.可是,非常多的 ...

  4. es6 初始化样式加载到head中

    Demo1:function loadCss(css) { css.forEach((path)=>{ console.log($('<link/>', { rel: 'styles ...

  5. struts2中配置全局日期类型转换器

    1.编写一个类,继承StrutsTypeConverter,实现其中的convertFromString和convertToString方法,该类如下: package me.edu.utils; i ...

  6. atom常用插件安装

    安装插件方法: File -Settings -Install 在搜索框里搜索你想要的插件,出来之后 点击install ,下图以 linter-selint 为例 ATOM常用插件推荐 simpli ...

  7. unity批量修改AssetBundleName与Variant

    批量修改指定路径下的资源的AssetBundleName与Variant. 脚本代码如下: using System.Collections; using System.Collections.Gen ...

  8. Unity 游戏对象消失 enable,destroy与active的区别

    gameObject.SetActive(false):是否在场景中停用该物体,停用后Hierarchy窗口呈灰色,用Find函数也找不到.如果该物体有子物体,要用SetActive Recursir ...

  9. Redis加锁与解锁

    Redis加锁 customerM = BaseMemCached.setMLock(customerId); /** * 个人账户表加锁 **/ public static CustomerM se ...

  10. CSS改变字体下划线颜色

    下图是网页中一个非常普通的列表. watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvQXVndXMzMzQ0/font/5a6L5L2T/fontsize/40 ...