有关opencv的学习(21)—图像滤波(2)

       之前介绍了用核心矩阵进行线性滤波的概念。这些滤波器通过移除或减弱高频成分,达到模糊图像的效果。下文中我们执行一种反向的变换,即放大图像中的高频成分。然后用本节介绍的高通滤波器进行边缘检测。


一、边缘检测概述

        边缘检测可以提取图像重要轮廓信息,减少图像内容, 可以用于分割图像、做特征提取等

        边缘检测的一般步骤:滤波----(滤出噪声対检测边缘的影响)

                                                增强----(可以将像素邻域强度变化凸显出来---梯度算子)

                                                检测----(阈值方法确定边缘)

       常用的边缘检测算子: Canny算子、Sobel算子、Scharr算子、Laplacian算子、Roberts算子、Prewitt算子。。。。


(1)、Canny边缘检测

       Canny边缘检测算子是John F.Canny于1986 年开发出来的一个多级边缘检测算法, Canny边缘检测算法以Canny的名字命名, 被很多人推崇为当今最优的边缘检测的算法。

Canny边缘检测步骤:

消除噪声:一般情况使用高斯平滑滤波器卷积降噪

计算梯度幅值和方向:如下图所示:


非极大值抑制: 排除非边缘像素

滞后阈值: 滞后阈值需要两个阈值(高阈值和低阈值),如下所示:

1、如果某一像素位置的幅值超过高阈值,该像素被保留为边缘像素;

2、如果某一像素位置的幅值小于低阈值,该像素被排除;

3、如果某一像素位置的幅值在两个阈值之间,该像素仅仅在连接到一个高于高阈值的像素时被保留。

Canny边缘检测函数----Canny()

函数原型:

CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,

                         double threshold1, double threshold2,

                         int apertureSize=3, bool L2gradient=false );

src: 输入原图像(一般为单通道8位图像);

dst: 输出边缘图像要求和src一样的尺寸和类型(单通道);

threshold1: 滞后阈值低阈值(用于边缘连接);

threshold2: 滞后阈值高阈值(控制边缘初始段),推荐高低阈值比值在2:1到3:1之间;

apertureSize: 表示孔径大小, 默认值3;

L2gradient: 计算图像梯度幅值的标识;

Canny边缘检测效果:




(2)、Sobel算子

       Sobel算子是一个主要用于边缘检测的离散微分算子, 它结合了高斯平滑和微分求导, 用来计算图像灰度函数的近似梯度。

计算过程:



Sobel边缘检测函数-----Sobel()

函数原型:

CV_EXPORTS_W 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: 输出图像要求和src一样的尺寸和类型;

ddepth: 输出图像的深度, 支持如下组合:


dx: X方向上的差分阶数;

dy: Y方向上的差分阶数;

ksize: 默认值3, 表示Sobel核大小, 1,3,5,7;

scale: 计算导数值时的缩放因子, 默认值1, 表示不缩放;

delta(δ): 表示在结果存入目标图之前可选的delta值, 默认值0;

borderType: 边界模式, 一般采用默认。

代码如下:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
        
    Mat image=imread("/Users/zhangxiaoyu/Desktop/1.png",0);//读取灰度图像
    if(image.empty())
    {
        cout<<"Error!/n";
        return -1;
    }
    
    cv::imshow("original image", image);
    
    cv::Mat result;
    
    cv::Mat grad_x,grad_y;
    cv::Mat abs_grad_x,abs_grad_y;
    
    //X方向
    Sobel(image, grad_x ,CV_16S, 1,0,3,1,1,BORDER_DEFAULT);
    convertScaleAbs(grad_x, abs_grad_x);
    cv::imshow("sobel-X image",abs_grad_x);
    
    //Y方向
    Sobel(image, grad_y ,CV_16S, 0,1,3,1,1,BORDER_DEFAULT);
    convertScaleAbs(grad_y, abs_grad_y);
    cv::imshow("sobel-Y image",abs_grad_y);
    
    //合并
    addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, result);
    cv::imshow("result image", result);
    
    waitKey(0);
    
}
运行结果如下所示:



(3)、Laplacian算子

          Laplacian算子是n维欧几里德中的一个二阶微分算子。

         Laplacian算子的定义:


Laplacian边缘检测函数---Laplacian()

函数原型:

CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,

                             int ksize=1, double scale=1, double delta=0,

                             int borderType=BORDER_DEFAULT );


src: 输入原图像(单通道8位图像)

dst: 输出边缘图像要求和src一样的尺寸和通道数;

ddepth: 目标图像的深度;

Ksize: 用于计算二阶导数的滤波器孔径大小, 须为正奇数, 默认值1;

scale: 可选比例因子, 默认值1;

delta: 可选参数δ, 默认值0;

borderType: 边界模式, 一般采用默认值。

代码如下:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
        
    Mat image=imread("/Users/zhangxiaoyu/Desktop/1.png",0);//读取灰度图像
    if(image.empty())
    {
        cout<<"Error!/n";
        return -1;
    }
    
    cv::imshow("original image", image);
    
    cv::Mat result;
    Laplacian(image, result, CV_16S,3,1,0,BORDER_DEFAULT);
    convertScaleAbs(result, result);
    
    cv::imshow("Laplacian image", result);
    
    waitKey(0);
    
}
结果如下:




































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章