一、Canny算子
Canny邊緣檢測算法是John F. Canny於1986年開發出來的一個多級邊緣檢測算法,也被很多人認爲是邊緣檢測的最優算法
-
消除噪聲:使用高斯平滑濾波器卷積降噪
-
計算梯度幅值和方向
梯度方向近似得到四個可能角度之一(一般0,45,90,135) -
非極大值抑制:這一步排除非邊緣像素,僅僅保留了一些細線條(候選邊緣)
-
滯後閾值:最後一步,Canny使用了滯後閾值,滯後閾值需要兩個閾值(高閾值和低閾值)
- 如果某一像素位置的幅值超過高閾值,該像素被保留爲邊緣像素。
- 如果某一像素的幅值小於低閾值,該像素被排除
- 如果某一像素位置的幅值在兩個閾值之間,該像素僅僅在連接到一個高於高閾值的像素時被保留
二、Canny
void cv::Canny ( InputArray image,
OutputArray edges,
double threshold1,
double threshold2,
int apertureSize = 3,
bool L2gradient = false
)
- Image: 輸入圖像
- edges: 輸出的邊緣圖像,8-bit單通道圖像,與輸入圖像有相同的尺寸。
- threshold1: 第一個滯後性閾值
- threshold2: 第二個滯後性閾值
- apertureSize: 表示應用的Sobel算子孔徑大小,有默認值3
- L2gradient: 一個計算圖像梯度幅值的標識,有默認值false
對於threshold1和threshold2兩個閾值來講,兩者較小的值用於邊緣連接而較大的值用來尋找邊緣的初始段。
三、示例
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
Mat src, gray_src, dst;
const char* windows_name = "Canny Demo Windows";
int value = 50, max_value = 255;
void Canny_Demo(int, void*);
int main() {
// 1. 加載圖像
src = imread("images/02.png");
if (!src.data) {
printf("Could not load ... ");
return -1;
}
namedWindow(windows_name, CV_WINDOW_AUTOSIZE);
imshow("src", src);
// 2. 轉成灰度圖像
cvtColor(src, gray_src, CV_BGR2BGRA);
// 3. 創建滾動條,拖動閾值
createTrackbar("低閾值:", windows_name, &value, max_value, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*) {
Mat blur_src;
//這裏的 blur 僅僅只是對原始圖像去幹擾,可有可無,Canny 函數內部已經實現了其算法的五個步驟
blur(gray_src, blur_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
//輸入圖像的顏色數據類型要求是8bit , 輸入圖像可以是 gray ,也可以是 src ,src的干擾線比gray多很多
Canny(blur_src, dst, value, value * 2, 3, false);//邊緣檢測提取,t1_value越大,檢測到的邊緣越少
imshow(windows_name, dst); //如果使用 ~dst 表示將圖像黑白反過來
Mat result;
result.create(src.size(), src.type());//創建一個相同類型,相同大小的Mat對象
//如果mask.at(i,j)爲1,則把src.at(i,j)賦給dst.at(i,j),如果mask.at(i,j)爲0,則dst.at(i,j)設爲0
src.copyTo(result, dst);
imshow("copyTo", result);
}