1. 程式人生 > >Opencv影象處理---Canny邊緣檢測

Opencv影象處理---Canny邊緣檢測

理論

Canny演算法旨在滿足三個主要標準:

  • 低錯誤率:意味著只檢測存在的邊緣。
  • 良好的定位:必須最小化檢測到的邊緣畫素和真實邊緣畫素之間的距離。
  • 最小響應:每個邊緣只有一個檢測器響應。

步驟

  • 過濾掉任何噪音。 高斯濾波器用於此目的。 可能使用的大小為5的高斯核心的示例如下所示:
  • 找到影象的強度梯度。 為此,我們遵循類似Sobel的程式:
  1. 應用一對卷積掩模(在x和y方向):
  2. 找到梯度強度和方向:
  • 應用非最大抑制。 這將刪除不被視為邊緣一部分的畫素。 因此,僅保留細線(候選邊緣)。
  • 遲滯:最後一步。 Canny確實使用了兩個閾值(上限和下限):
  1. 如果畫素梯度高於上閾值,則該畫素被接受為邊緣
  2. 如果畫素梯度值低於下閾值,則拒絕它
  3. 如果畫素梯度在兩個閾值之間,則僅當它連線到高於上閾值的畫素時才接受它。

程式碼


#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
Mat src, src_gray;
Mat dst, detected_edges;
int edgeThresh = 1;
int lowThreshold;
int const max_lowThreshold = 100;
int ratio = 3;
int kernel_size = 3;
const char* window_name = "Edge Map";
static void CannyThreshold(int, void*)
{
    blur( src_gray, detected_edges, Size(3,3) );
    Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
    dst = Scalar::all(0);
    src.copyTo( dst, detected_edges);
    imshow( window_name, dst );
}
int main( int, char** argv )
{
  src = imread( argv[1] );
  if( src.empty() )
    { return -1; }
  dst.create( src.size(), src.type() );
  cvtColor( src, src_gray, COLOR_BGR2GRAY );
  namedWindow( window_name, WINDOW_AUTOSIZE );
  createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
  CannyThreshold(0, 0);
  waitKey(0);
  return 0;
}

解釋

  • 建立一些所需的變數:
  1. 我們建立一個較低的比率:上限閾值為3:1(可變比例)
  2. 我們將核心大小設定為3(用於由Canny函式在內部執行的Sobel操作)
  3. 我們為下限閾值設定了最大值100。
  • 載入源影象:
  • 建立一個src相同型別和大小的矩陣(將是dst)
  • 將影象轉換為灰度(使用函式cv :: cvtColor:)
  • 建立一個視窗以顯示結果
  • 建立一個滑塊欄,供使用者輸入Canny探測器的下限:
  1. 滑動條控制的變數是低閾值,具有最大低閾值限制(我們之前設定為100)
  2. 每次滑動條註冊一個動作時,都會呼叫回撥函式CannyThreshold。
  • 讓我們一步一步檢查CannyThreshold函式:
  1. 首先,我們使用核心大小為3的過濾器模糊影象:
  2. 其次,我們應用OpenCV函式cv :: Canny:
  • 我們用零填充dst影象(意味著影象是完全黑色的)。
  • 最後,我們將使用函式cv :: Mat :: copyTo僅對映影象中標識為邊的區域(在黑色背景上)。
  • 我們顯示結果:

效果

在編譯上面的程式碼之後,我們可以執行它作為引數給出影象的路徑。 例如,使用以下影象作為輸入:

移動滑塊,嘗試不同的閾值,我們得到以下結果: