OpenCV中邊緣檢測:Canny算子,Sobel算子,Laplace算子,Scharr濾波

1、基於OpenCV的邊緣檢測步驟

  1. 濾波:邊緣檢測算法主要是基於圖像強度的一階和二階導數,但是導數對於噪聲很敏感,因此需要採用濾波器來改善與噪聲有關的邊緣檢測器的性能。簡言之,消除噪聲。
  2. 增強:增強邊緣的基礎是確定圖像各點鄰域強度的變化值。增強算法可以將灰度點鄰域強度值有顯著變化的點凸顯出來。簡言之,使邊界輪廓更加明顯。
  3. 檢測:鄰域中有很多的點的梯度值較大,但是在特定的應用中,這些點並不是要找的邊緣點,需要取捨。簡言之,選出邊緣點。

2、Canny算子

Canny算子是John F.Canny於1986年開發出來的一個多級邊緣檢測算法。

void Canny(InputArray image,OutputArray edges,
         double threshold1, double threshold2, int apertureSize=3,bool L2gradient=false ) 

參數解釋:
第一個參數,InputArray類型的image,輸入圖像,即源圖像,填Mat類的對象即可,且需爲單通道8位圖像。
第二個參數,OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和類型。
第三個參數,double類型的threshold1,第一個滯後性閾值。
第四個參數,double類型的threshold2,第二個滯後性閾值。
第五個參數,int類型的apertureSize,表示應用Sobel算子的孔徑大小,其有默認值3。
第六個參數,bool類型的L2gradient,一個計算圖像梯度幅值的標識,有默認值false。
需要注意的是,這個函數閾值1和閾值2兩者的小者用於邊緣連接,而大者用來控制強邊緣的初始段,推薦的高低閾值比在2:1到3:1之間。
#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("C:\\Users\\cf\\Desktop\\測試數據\\test00.jpg");
	cout << img.size() << endl;
	imshow("原圖",img);

	Mat dst,edge,gray;
	//創建與img同類型和大小的矩陣
	dst.create(img.size(), img.type());
	//轉灰度圖像
	cvtColor(img, gray, COLOR_BGR2GRAY);
	//3*3 內核降噪(均值濾波)
	blur(gray, edge, Size(3, 3));
	//使用canny算子
	Canny(edge, edge, 3, 9, 3);
	imshow("Canny邊緣檢測", edge);

	//將dst內所有元素清0
	dst = Scalar::all(0);
	img.copyTo(dst, edge);
	imshow("Canny邊緣檢測效果", dst);

	waitKey();
	return 0;
}

3、Sobel算子

Sobel算子是一個主要用於邊緣檢測的離散微分算子(discrete differentiation operator),它結合高斯平滑和微分求導。用來計算圖像灰度函數的近似函數。

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 );  

參數解釋:
第一個參數,InputArray 類型的src,爲輸入圖像,填Mat類型即可。
第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。
第三個參數,int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:
若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_64F, 取ddepth = -1/CV_64F
第四個參數,int類型dx,x 方向上的差分階數。
第五個參數,int類型dy,y方向上的差分階數。
第六個參數,int類型ksize,有默認值3,表示Sobel核的大小;必須取1,3,5或7。
第七個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。
第八個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。
第九個參數, int類型的borderType,我們的老朋友了(萬年是最後一個參數),邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。
#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("C:\\Users\\cf\\Desktop\\測試數據\\test00.jpg");
	cout << img.size() << endl;
	imshow("原圖",img);

	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;
	//求x方向的梯度
	Sobel(img, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("x方向Sobel", abs_grad_x);

	//求y方向的梯度
	Sobel(img, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("y方向Sobel", abs_grad_y);

	//合併梯度(近似)
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
	imshow("整體效果圖", dst);
	waitKey();
	return 0;
}

4、Laplacian算子

Laplacian算子是n維歐幾里得空間中的一個二階微分算子。

void Laplacian(InputArray src,OutputArray dst, 
                int ddepth, int ksize=1, double scale=1, 
                double delta=0, intborderType=BORDER_DEFAULT ); 
參數解釋:
第一個參數,InputArray類型的image,輸入圖像,即源圖像,填Mat類的對象即可,且需爲單通道8位圖像。
第二個參數,OutputArray類型的edges,輸出的邊緣圖,需要和源圖片有一樣的尺寸和通道數。
第三個參數,int類型的ddept,目標圖像的深度。
第四個參數,int類型的ksize,用於計算二階導數的濾波器的孔徑尺寸,大小必須爲正奇數,且有默認值1。
第五個參數,double類型的scale,計算拉普拉斯值的時候可選的比例因子,有默認值1。
第六個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。
第七個參數, int類型的borderType,邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate()處得到更詳細的信息。

Laplacian( )函數其實主要是利用sobel算子的運算。它通過加上sobel算子運算出的圖像x方向和y方向上的導數,來得到我們載入圖像的拉普拉斯變換結果。

#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("C:\\Users\\cf\\Desktop\\測試數據\\test00.jpg");
	cout << img.size() << endl;
	imshow("原圖",img);

	Mat gray, dst, abs_dst;
	//使用高斯濾波消除噪聲
	GaussianBlur(img, img, Size(3, 3), 0, 0, BORDER_DEFAULT);
	//轉爲灰度圖
	cvtColor(img, gray, COLOR_BGR2GRAY);
	//使用Laplace函數
	Laplacian(gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(dst, abs_dst);
	imshow("Laplacian效果圖", abs_dst);
	waitKey();
	return 0;
}

5、scharr濾波器

scharr一般我就直接稱它爲濾波器,而不是算子。

void Scharr( InputArray src, OutputArray dst, int ddepth, int dx, int dy,
 double scale=1, double delta=0, intborderType=BORDER_DEFAULT )
參數詳解:
第一個參數,InputArray 類型的src,爲輸入圖像,填Mat類型即可。
第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。
第三個參數,int類型的ddepth,輸出圖像的深度,支持如下src.depth()和ddepth的組合:
若src.depth() = CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
若src.depth() = CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_32F, 取ddepth =-1/CV_32F/CV_64F
若src.depth() = CV_64F, 取ddepth = -1/CV_64F
第四個參數,int類型dx,x方向上的差分階數。
第五個參數,int類型dy,y方向上的差分階數。
第六個參數,double類型的scale,計算導數值時可選的縮放因子,默認值是1,表示默認情況下是沒有應用縮放的。我們可以在文檔中查閱getDerivKernels的相關介紹,來得到這個參數的更多信息。
第七個參數,double類型的delta,表示在結果存入目標圖(第二個參數dst)之前可選的delta值,有默認值0。
第八個參數, int類型的borderType,我們的老朋友了(萬年是最後一個參數),邊界模式,默認值爲BORDER_DEFAULT。這個參數可以在官方文檔中borderInterpolate處得到更詳細的信息。
#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;

int main()
{
	Mat img = imread("C:\\Users\\cf\\Desktop\\測試數據\\test00.jpg");
	cout << img.size() << endl;
	imshow("原圖",img);

	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;
	//求x方向的梯度
	Scharr(img, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("X方向Scharr", abs_grad_x);
	//求y方向的梯度
	Scharr(img, grad_y, CV_16S, 0, 1, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_y, abs_grad_y);
	imshow("Y方向Scharr", abs_grad_y);

	//合併梯度
	addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
	imshow("Scharr效果圖", dst);
	waitKey();
	return 0;
}

6、參考

https://blog.csdn.net/weixin_40647819/article/details/80029858

https://www.cnblogs.com/skyfsm/p/6879265.html

https://blog.csdn.net/huayunhualuo/article/details/81478037

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