邊緣檢測:
一、canny算子
Canny邊緣檢測根據對信噪比與定位乘積進行測度,得到最優化逼近算子,也就是Canny算子。類似與 LoG 邊緣檢測方法,也屬於先平滑后求導數的方法。
二、canny算法描述
1.首先進行高斯平滑濾波;

2、然后計算像素點的梯度(利用sobel算子)

3、計算幅值和夾角

4、非極大值抑制(NMS)幅值和夾角,如下圖所示,就是比較梯度方向前后像素梯度的大小。

上圖中左右圖:g1、g2、g3、g4都代表像素點,很明顯它們是c的八領域中的4個,左圖中c點是我們需要判斷的點,藍色的直線是它的梯度方向,也就是說c如果是局部極大值,它的梯度幅值M需要大於直線與g1g2和g2g3的交點,dtmp1和dtmp2處的梯度幅值。但是dtmp1和dtmp2不是整像素,而是亞像素,也就是坐標是浮點的,那怎么求它們的梯度幅值呢?線性插值,例如dtmp1在g1、g2之間,g1、g2的幅值都知道,我們只要知道dtmp1在g1、g2之間的比例,就能得到它的梯度幅值,而比例是可以靠夾角計算出來的,夾角又是梯度的方向。
寫個線性插值的公式:設g1的幅值M(g1),g2的幅值M(g2),則dtmp1可以很得到:
M(dtmp1)=w*M(g2)+(1-w)*M(g1)
其中w=distance(dtmp1,g2)/distance(g1,g2)
distance(g1,g2) 表示兩點之間的距離。實際上w是一個比例系數,這個比例系數可以通過梯度方向(幅角的正切和余切)得到。
5、雙閾值選取
-
將低於閾值的所有值賦零,得到圖像的邊緣陣列
- 閾值τ取得太低->假邊緣
- 閾值τ取得太高->部分輪廊丟失
Canny算法中減少假邊緣數量的方法是采用雙閾值法。選擇兩個閾值,根據高閾值得到一個邊緣圖像,這樣一個圖像含有很少的假邊緣,但是由於閾值較高,產生的圖像邊緣可能不閉合,為解決這樣一個問題采用了另外一個低閾值。
在高閾值圖像中把邊緣鏈接成輪廓,當到達輪廓的端點時,該算法會在斷點的8鄰域點中尋找滿足低閾值的點,再根據此點收集新的邊緣,直到整個圖像邊緣閉合。
三、Canny方法
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false)
- 第一個參數,InputArray類型的image,輸入圖像,填Mat類對象即可,且需為單通道8位圖像
- 第二個參數,OutputArray類型的edges,輸出邊緣圖,和源圖像有一樣的尺寸和類型
- 第三個參數,double類型的threshold1,第一個滯后性閾值
- 第四個參數,double類型的threshold2,第二個滯后性閾值
- 第五個參數,int類型的apertureSize,表示應用Sobel算子的孔徑大小,默認值3
- 第六個參數,bool類型的L2gradient,一個計算圖像梯度幅值的標識,默認值false
四、opencv中的實現
1、圖像灰度化;
2、高斯濾波(blur)
3、計算梯度
4、用雙閾值方法檢測和連接邊緣
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <math.h>
using namespace cv;
{
Mat img = imread("lena.jpg", CV_LOAD_IMAGE_COLOR);
if(img.empty())
return -1;
Mat src_gray,src_blur,dst;
cvtColor(img,src_gray,CV_BGR2GRAY);
blur(src_gray,src_blur,Size(3,3));
Canny(src_blur,dst,30,200);
namedWindow( "lena", CV_WINDOW_AUTOSIZE );
imshow("lena", img);
imshow("canny",dst);
waitKey(0);
return 0;
}

