天天看點

opencv-Canny()函數

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