前言
在上一章中描述了Laplance邊緣檢測(cè)算子,詳細(xì)描述可點(diǎn)擊查看(http://www.reibang.com/writer#/notebooks/47386368/notes/82819100)
目標(biāo)
本章中枉长,將學(xué)習(xí):
- Canny算子介紹
- 相關(guān)API
- 代碼演示
Canny算子介紹
Canny邊緣檢測(cè)是一種非常流行的邊緣檢測(cè)算法冀续,是John Canny在1986年提出的。它是一個(gè)多階段的算法必峰,即由多個(gè)步驟構(gòu)成洪唐。
1.圖像降噪:通常使用高斯模糊;
2.計(jì)算圖像梯度:Sobel/Scharr吼蚁;
3.非極大值抑制凭需;
4.高低閾值輸出二值圖像;
第一步:圖像降噪肝匆,我們知道梯度算子可以用于增強(qiáng)圖像粒蜈,本質(zhì)上是通過(guò)增強(qiáng)邊緣輪廓來(lái)實(shí)現(xiàn)的,也就是說(shuō)是可以檢測(cè)到邊緣的旗国。但是枯怖,它們受噪聲的影響都很大。那么能曾,我們第一步就是想到要先取出噪聲度硝,因?yàn)樵肼暰褪腔叶茸兓艽蟮牡胤剑匀菀妆蛔R(shí)別為偽邊緣寿冕。
第二步:計(jì)算圖像梯度蕊程,得到可能邊緣。計(jì)算圖像梯度能夠得到圖像的邊緣驼唱,因?yàn)樘荻仁腔叶茸兓黠@的地方藻茂,而邊緣也是灰度變化明顯的地方。當(dāng)然這一步只能得到可能的邊緣曙蒸。因?yàn)榛叶茸兓牡胤娇赡苁沁吘壈浦危部赡懿皇沁吘墶_@一步就有了所有可能是邊緣的集合纽窟。
第三步肖油,非極大值抑制。通潮鄹郏灰度變化的地方都比較集中森枪,將局部范圍內(nèi)的梯度方向上,灰度變化最大的保留下來(lái)审孽,其它的不保留县袱,這樣可以剔除掉一大部分的點(diǎn)。將有多個(gè)像素寬的邊緣變成一個(gè)單像素寬的邊緣佑力。即“胖邊緣”變成“瘦邊緣”式散。
第四步,雙閾值篩選打颤。通過(guò)非極大值抑制后暴拄,仍然有很多的可能邊緣點(diǎn)漓滔,進(jìn)一步的設(shè)置一個(gè)雙閾值,即低閾值(low)乖篷,高閾值(high)响驴。灰度變化大于high的撕蔼,設(shè)置為強(qiáng)邊緣像素豁鲤,低于low的,剔除鲸沮。在low和high之間的設(shè)置為弱邊緣琳骡。進(jìn)一步判斷,如果其領(lǐng)域內(nèi)有強(qiáng)邊緣像素诉探,保留日熬,如果沒(méi)有棍厌,剔除肾胯。
相關(guān)API
Canny(
InputArray src, // 8-bit的輸入圖像
OutputArray edges,// 輸出邊緣圖像, 一般都是二值圖像耘纱,背景是黑色
double threshold1,// 低閾值敬肚,常取高閾值的1/2或者1/3
double threshold2,// 高閾值
int aptertureSize,// Soble算子的size,通常3x3束析,取值3
bool L2gradient // (是否采用更精確的方式計(jì)算圖像梯度)選擇 true表示是L2來(lái)歸一化艳馒,否則用L1歸一化
)
關(guān)于L2gradient參數(shù):
-
如果為true,計(jì)算圖像梯度的時(shí)候會(huì)使用(更加精確)L2 员寇;如果為false弄慰,計(jì)算圖像梯度的時(shí)候會(huì)使用L1; 默認(rèn)情況一般選擇是L1蝶锋,參數(shù)設(shè)置為false.陆爽。
梯度參數(shù).png
代碼演示
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
Mat src, gray_src, dst;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("D:/linuxkiss/images/leo.png");
if (!src.data) {
printf("could not load image...\n");
return -1;
}
char INPUT_TITLE[] = "input image";
namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
imshow(INPUT_TITLE, src);
cvtColor(src, gray_src, CV_BGR2GRAY);
createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*) {
Mat edge_output;
blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
//------api調(diào)用------
Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);
//dst.create(src.size(), src.type());
//src.copyTo(dst, edge_output);// 將原圖的使用Canny算子做掩膜拷貝對(duì)應(yīng)位置像素,比較耗時(shí)
//imshow(OUTPUT_TITLE, ~edge_output);// 顯示Canny算子處理后的取反圖像
imshow(OUTPUT_TITLE, edge_output);// 顯示Canny算子處理后的圖像
}