之前介紹了用核心矩陣進行線性濾波的概念。這些濾波器通過移除或減弱高頻成分,達到模糊圖像的效果。下文中我們執行一種反向的變換,即放大圖像中的高頻成分。然後用本節介紹的高通濾波器進行邊緣檢測。
一、邊緣檢測概述
邊緣檢測可以提取圖像重要輪廓信息,減少圖像內容, 可以用於分割圖像、做特徵提取等。
邊緣檢測的一般步驟:濾波----(濾出噪聲対檢測邊緣的影響)
增強----(可以將像素鄰域強度變化凸顯出來---梯度算子)
檢測----(閾值方法確定邊緣)
常用的邊緣檢測算子: 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);
}
結果如下: