有關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);
    
}
結果如下:




































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