1. 程式人生 > >OpenCV3邊緣檢測:Canny運算元/Sobel運算元/Laplace運算元/Scharr濾波器

OpenCV3邊緣檢測:Canny運算元/Sobel運算元/Laplace運算元/Scharr濾波器

邊緣檢測的一般步驟

1)濾波:邊緣檢測的演算法主要是基於影象強度的一階和二階導數,但導數通常對噪聲很敏感,因此必須採用濾波器來改善與噪聲有關的邊緣檢測器的效能。常見的濾波方法主要有高斯濾波,即採用離散化的高斯函式產生一組歸一化的高斯核(具體見“高斯濾波原理及其程式設計離散化實現方法”一文),然後基於高斯核函式對影象灰度矩陣的每一點進行加權求和。
2)增強:增強邊緣的基礎是確定影象各點鄰域強度的變化值。增強演算法可以將影象灰度點鄰域強度值有顯著變化的點凸顯出來。在具體程式設計實現時,可通過計算梯度幅值來確定。
3)檢測:經過增強的影象,往往鄰域中有很多點的梯度值比較大,而在特定的應用中,這些點並不是我們要找的邊緣點,所以應該採用某種方法來對這些點進行取捨。實際工程中,常用的方法是通過閾值化方法來檢測。
另外,需要注意,下文中講到的Laplace

運算元,sobel運算元和Scharr運算元都是帶方向的。

Canny邊緣檢測演算法以Canny的名字命名,被很多人推崇為當今最優的邊緣檢測的演算法。

其中,Canny 的目標是找到一個最優的邊緣檢測演算法,讓我們看一下最優邊緣檢測的三個主要評價標準:
1.低錯誤率: 標識出盡可能多的實際邊緣,同時儘可能的減少噪聲產生的誤報。
2.高定位性: 標識出的邊緣要與影象中的實際邊緣儘可能接近。
3.最小響應: 影象中的邊緣只能標識一次,並且可能存在的影象噪聲不應標識為邊緣。
為了滿足這些要求 Canny 使用了變分法,這是一種尋找滿足特定功能的函式的方法。最優檢測使用四個指數函式項的和表示,但是它非常近似於高斯函式的一階導數。

Sobel 運算元是一個主要用作邊緣檢測的離散微分運算元 (discrete differentiation operator)。 它Sobel運算元結合了高斯平滑和微分求導,用來計算影象灰度函式的近似梯度。
Laplacian 運算元是n維歐幾里德空間中的一個二階微分運算元,定義為梯度grad()的散度div()
**Laplacian( )**函式其實主要是利用sobel運算元的運算。它通過加上sobel運算元運算出的影象x方向和y方向上的導數,來得到我們載入影象的拉普拉斯變換結果。
scharr一般我就直接稱它為濾波器,而不是運算元。它在OpenCV中主要是配合Sobel運算元的運算而存在的。

示例

//-----------------------------------【標頭檔案包含部分】---------------------------------------
//		描述:包含程式所依賴的標頭檔案
//---------------------------------------------------------------------------------------------- 
#include "pch.h"
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//-----------------------------------【名稱空間宣告部分】--------------------------------------
//		描述:包含程式所使用的名稱空間
//----------------------------------------------------------------------------------------------- 
using namespace cv;


//-----------------------------------【全域性變數宣告部分】--------------------------------------
//		描述:全域性變數宣告
//-----------------------------------------------------------------------------------------------
//原圖,原圖的灰度版,目標圖
Mat g_srcImage, g_srcGrayImage, g_dstImage;

//Canny邊緣檢測相關變數
Mat g_cannyDetectedEdges;
int g_cannyLowThreshold = 1;//TrackBar位置引數  

//Sobel邊緣檢測相關變數
Mat g_sobelGradient_X, g_sobelGradient_Y;
Mat g_sobelAbsGradient_X, g_sobelAbsGradient_Y;
int g_sobelKernelSize = 1;//TrackBar位置引數  

//Scharr濾波器相關變數
Mat g_scharrGradient_X, g_scharrGradient_Y;
Mat g_scharrAbsGradient_X, g_scharrAbsGradient_Y;


//-----------------------------------【全域性函式宣告部分】--------------------------------------
//		描述:全域性函式宣告
//-----------------------------------------------------------------------------------------------
static void ShowHelpText();
static void on_Canny(int, void*);//Canny邊緣檢測視窗滾動條的回撥函式
static void on_Sobel(int, void*);//Sobel邊緣檢測視窗滾動條的回撥函式
void Scharr();//封裝了Scharr邊緣檢測相關程式碼的函式


//-----------------------------------【main( )函式】--------------------------------------------
//		描述:控制檯應用程式的入口函式,我們的程式從這裡開始
//-----------------------------------------------------------------------------------------------
int main(int argc, char** argv)
{
	//改變console字型顏色
	system("color 2F");

	//顯示歡迎語
	ShowHelpText();

	//載入原圖
	g_srcImage = imread("1.jpg");
	if (!g_srcImage.data) { printf("讀取srcImage錯誤~! \n"); return false; }

	//顯示原始圖
	namedWindow("【原始圖】");
	imshow("【原始圖】", g_srcImage);

	// 建立與src同類型和大小的矩陣(dst)
	g_dstImage.create(g_srcImage.size(), g_srcImage.type());

	// 將原影象轉換為灰度影象
	cvtColor(g_srcImage, g_srcGrayImage, CV_BGR2GRAY);

	// 建立顯示視窗
	namedWindow("【效果圖】Canny邊緣檢測", CV_WINDOW_AUTOSIZE);
	namedWindow("【效果圖】Sobel邊緣檢測", CV_WINDOW_AUTOSIZE);

	// 建立trackbar
	createTrackbar("引數值:", "【效果圖】Canny邊緣檢測", &g_cannyLowThreshold, 120, on_Canny);
	createTrackbar("引數值:", "【效果圖】Sobel邊緣檢測", &g_sobelKernelSize, 3, on_Sobel);

	// 呼叫回撥函式
	on_Canny(0, 0);
	on_Sobel(0, 0);

	//呼叫封裝了Scharr邊緣檢測程式碼的函式
	Scharr();

	//輪詢獲取按鍵資訊,若按下Q,程式退出
	while ((char(waitKey(1)) != 'q')) {}

	return 0;
}


//-----------------------------------【ShowHelpText( )函式】----------------------------------
//		描述:輸出一些幫助資訊
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
	//輸出一些幫助資訊
	printf("\n\n\t嗯。執行成功,請調整滾動條觀察影象效果~\n\n"
		"\t按下“q”鍵時,程式退出~!\n");
}


//-----------------------------------【on_Canny( )函式】----------------------------------
//		描述:Canny邊緣檢測視窗滾動條的回撥函式
//-----------------------------------------------------------------------------------------------
void on_Canny(int, void*)
{
	// 先使用 3x3核心來降噪
	blur(g_srcGrayImage, g_cannyDetectedEdges, Size(3, 3));

	// 執行我們的Canny運算元
	Canny(g_cannyDetectedEdges, g_cannyDetectedEdges, g_cannyLowThreshold, g_cannyLowThreshold * 3, 3);

	//先將g_dstImage內的所有元素設定為0 
	g_dstImage = Scalar::all(0);

	//使用Canny運算元輸出的邊緣圖g_cannyDetectedEdges作為掩碼,來將原圖g_srcImage拷到目標圖g_dstImage中
	g_srcImage.copyTo(g_dstImage, g_cannyDetectedEdges);

	//顯示效果圖
	imshow("【效果圖】Canny邊緣檢測", g_dstImage);
}



//-----------------------------------【on_Sobel( )函式】----------------------------------
//		描述:Sobel邊緣檢測視窗滾動條的回撥函式
//-----------------------------------------------------------------------------------------
void on_Sobel(int, void*)
{
	// 求 X方向梯度
	Sobel(g_srcImage, g_sobelGradient_X, CV_16S, 1, 0, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT);
	convertScaleAbs(g_sobelGradient_X, g_sobelAbsGradient_X);//計算絕對值,並將結果轉換成8位

	// 求Y方向梯度
	Sobel(g_srcImage, g_sobelGradient_Y, CV_16S, 0, 1, (2 * g_sobelKernelSize + 1), 1, 1, BORDER_DEFAULT);
	convertScaleAbs(g_sobelGradient_Y, g_sobelAbsGradient_Y);//計算絕對值,並將結果轉換成8位

	// 合併梯度
	addWeighted(g_sobelAbsGradient_X, 0.5, g_sobelAbsGradient_Y, 0.5, 0, g_dstImage);

	//顯示效果圖
	imshow("【效果圖】Sobel邊緣檢測", g_dstImage);

}


//-----------------------------------【Scharr( )函式】----------------------------------
//		描述:封裝了Scharr邊緣檢測相關程式碼的函式
//-----------------------------------------------------------------------------------------
void Scharr()
{
	// 求 X方向梯度
	Scharr(g_srcImage, g_scharrGradient_X, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_X, g_scharrAbsGradient_X);//計算絕對值,並將結果轉換成8位

	// 求Y方向梯度
	Scharr(g_srcImage, g_scharrGradient_Y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(g_scharrGradient_Y, g_scharrAbsGradient_Y);//計算絕對值,並將結果轉換成8位

	// 合併梯度
	addWeighted(g_scharrAbsGradient_X, 0.5, g_scharrAbsGradient_Y, 0.5, 0, g_dstImage);

	//顯示效果圖
	imshow("【效果圖】Scharr濾波器", g_dstImage);
}