【OpenCV(C++)】圖像變換:邊緣檢測

邊緣檢測的步驟

  • 濾波
    邊緣檢測的算法主要是基於圖像強度的一階和二階導數,但導數通常對噪聲很敏感,因此必須採用濾波器來改善與噪聲有關的邊緣檢測器的性能。
  • 增強
    增強邊緣的基礎是確定圖像各點鄰域的變化值。增強算法可以將圖像灰度點鄰域強度值有顯著變化的點凸顯出來。
  • 檢測
    經過增強的圖像,往往鄰域中有很多點的梯度值比較大,而在特定的應用中,這些點並不是要找的邊緣點,所以應該採用某種方法來對這些點進行取捨。

Canny算子

canny邊緣檢測算子是一個多級邊緣檢測算法。
最優邊緣檢測的評價標準:低錯誤率高定位性最小響應。爲了滿足這些要求,Canny使用了變分法,這是一種尋找滿足特定功能的函數的方法。最優檢測用4個指數函數項的和表示,但是它非常近似於高斯函數的一階導數。

Canny函數利用Canny算子來進行圖像的邊緣檢測操作。

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

在這裏插入圖片描述

#include<opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{
	Mat srcImage = imread("fg.jpg");
	imshow("[原圖]Canny邊緣檢測", srcImage);

	Mat dstImage, edge, grayImage;
	dstImage.create(srcImage.size(), srcImage.type());
	cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
	blur(grayImage, edge, Size(3, 3));
	Canny(edge, edge, 3, 9, 3);
	imshow("[效果圖]Canny邊緣檢測", edge);
	waitKey(0);

	return 0;
}

運行效果如下:
在這裏插入圖片描述

Sobel算子

Sobel算子是一個主要用於邊緣檢測的離散微分算子。它結合了高斯平滑和微分求導,用來計算圖像灰度函數的近似梯度。在圖像的任何一點使用此算子,都將會產生對應的梯度矢量或是其法矢量。

Sobel函數使用擴展的Sobel算子,來計算一階、二階、三階或混合圖像差分。

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

在這裏插入圖片描述

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

using namespace cv;

int main()
{
	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;

	Mat src = imread("fg.jpg");

	imshow("【原始圖】sobel邊緣檢測", src);

	Sobel(src, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("【效果圖】 X方向Sobel", abs_grad_x);

	Sobel(src, 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("【效果圖】整體方向Sobel", dst);

	waitKey(0);
	return 0;
}

運行效果如下:
在這裏插入圖片描述

Laplacian算子

Laplacian算子是n維歐幾里得空間中的一個二階微分算子,定義爲梯度grad的散度div。根據圖像處理的原理可知,二階導數可以用來進行邊緣檢測,因爲圖像是二維的,需要在兩個方向進行求導。使用Laplacian算子將會使求導過程變得簡單。
Laplacian算子的定義:
在這裏插入圖片描述
Laplacian函數可以計算出圖像經過拉普拉斯變換後的結果。

void Laplacian(
InputArray src,
OutputArray dst ,
int ddepth,
int ksize=1,
double scale=1,
double delta=0 ,
intborderType=BORDER_DEFAULT) ;

在這裏插入圖片描述

#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;

int main()
{
	Mat src, src_gray, dst, abs_dst;
 
	src = imread("fg.jpg");
 
	imshow("【原始圖】圖像Laplace變換", src);

	GaussianBlur(src, src, Size(3, 3), 0, 0, BORDER_DEFAULT);

	cvtColor(src, src_gray, CV_RGB2GRAY);

	Laplacian(src_gray, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);

	convertScaleAbs(dst, abs_dst);

	imshow("【效果圖】圖像Laplace變換", abs_dst);

	waitKey(0);

	return 0;
}

運行效果如下:
在這裏插入圖片描述

scharr濾波器

我們一般直接稱scharr爲濾波器,而不是算子。它在OpenCV中主要是配合Sobel算子的運算而存在的。
使用Scharr濾波器運算符計算x或y方向的圖像差分,其參數變量和Sobel基本上是一樣的,除了沒有ksize核的大小。

void Scharr(
InputArray src,
OutputArray dst,
int ddepth,
int dx,
int dy,
double scale=1 ,
double delta=0 ,
intborderType=BORDER_DEFAULT) ;
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;



int main()
{

	Mat grad_x, grad_y;
	Mat abs_grad_x, abs_grad_y, dst;

	Mat src = imread("fg.jpg");

	imshow("【原始圖】Scharr濾波器", src);

	Scharr(src, grad_x, CV_16S, 1, 0, 1, 0, BORDER_DEFAULT);
	convertScaleAbs(grad_x, abs_grad_x);
	imshow("【效果圖】 X方向Scharr", abs_grad_x);

	Scharr(src, 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(0);
	return 0;
}

運行效果如下:
在這裏插入圖片描述

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