canny對邊緣進行檢測,有三個原則:
1、信噪比原則:以低的錯誤率檢測邊緣,也即意味着需要盡可能準确的捕獲圖像中盡可能多的邊緣。
2、定位精度原則:檢測到的邊緣應精确定位在真實邊緣的中心。
3、機關緣響應原則:圖像中給定的邊緣應隻被标記一次,并且在可能的情況下,圖像的噪聲不應産生假的邊緣。
基本思想:首先對圖像進行高斯濾波平滑圖像,然後采用非極值抑制技術進行處理得到最後的邊緣圖像。
實作步驟:
1、高斯平滑濾波。為了去除噪聲
2、計算梯度強度和方向。邊緣的最重要的特征是灰階值劇烈變化,如果把灰階值看成二進制函數值,那麼灰階值的變化可以用二進制函數的”導數“(或者稱為梯度)來描述。由于圖像是離散資料,導數可以用差分值來表示,差分在實際工程中就是灰階差,說人話就是兩個像素的內插補點。一個像素點有8鄰域,那麼分上下左右斜對角,是以Canny算法使用四個算子來檢測圖像中的水準、垂直和對角邊緣。算子是以圖像卷積的形式來計算梯度,比如Roberts,Prewitt,Sobel等,這裡選用Sobel算子來計算二維圖像在x軸和y軸的差分值
3、非極大值抑制。sobel算子檢測出來的邊緣太粗了,我們需要抑制那些梯度不夠大的像素點,隻保留最大的梯度,進而達到瘦邊的目的。這些梯度不夠大的像素點很可能是某一條邊緣的過渡點。按照高數上二維函數的極大值的定義,即對點(x0,y0)的某個鄰域内所有(x,y)都有f(x,y)≤(f(x0,y0),則稱f在(x0,y0)具有一個極大值,極大值為f(x0,y0)。簡單方案是判斷一個像素點的8鄰域與中心像素誰更大,但這很容易篩選出噪聲,是以我們需要用梯度和梯度方向來輔助确定。
//---------------------------------【頭檔案、命名空間包含部分】----------------------------
// 描述:包含程式所使用的頭檔案和命名空間
//------------------------------------------------------------------------------------------------
#include <opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
//-----------------------------------【main( )函數】-------------------------------------------
// 描述:控制台應用程式的入口函數,我們的程式從這裡開始
//-----------------------------------------------------------------------------------------------
int main()
{
//載入原始圖
Mat srcImage = imread("1.jpg"); //工程目錄下應該有一張名為1.jpg的素材圖
Mat srcImage1 = srcImage.clone();
//顯示原始圖
imshow("【原始圖】Canny邊緣檢測", srcImage);
//----------------------------------------------------------------------------------
// 二、高階的canny用法,轉成灰階圖,降噪,用canny,最後将得到的邊緣作為掩碼,拷貝原圖到效果圖上,得到彩色的邊緣圖
//----------------------------------------------------------------------------------
Mat dstImage, edge, grayImage;
// 【1】建立與src同類型和大小的矩陣(dst)
dstImage.create(srcImage1.size(), srcImage1.type());
// 【2】将原圖像轉換為灰階圖像
cvtColor(srcImage1, grayImage, COLOR_BGR2GRAY);
// 【3】先用使用 3x3核心來降噪
blur(grayImage, edge, Size(3, 3));
// 【4】運作Canny算子
Canny(edge, edge, 3, 9, 3);
//【5】将g_dstImage内的所有元素設定為0
dstImage = Scalar::all(0);
//【6】使用Canny算子輸出的邊緣圖g_cannyDetectedEdges作為掩碼,來将原圖g_srcImage拷到目标圖g_dstImage中
srcImage1.copyTo(dstImage, edge);
//【7】顯示效果圖
imshow("【效果圖】Canny邊緣檢測2", dstImage);
waitKey(0);
return 0;
}