canny運算元中的非極大值抑制(non-maximum suppression)分析
在常見的邊緣檢測運算元或輪廓檢測相關演算法中都有非極大值抑制這一步,然而對與非極大值抑制在這些邊緣檢測運算元中應用,在理解可能有點似懂非懂。本文將介紹canny演算法中的非極大值抑制,canny運算元中的非極大值抑制是指沿著梯度方向上進行非極大值的抑制。
首先,我們來看看canny運算元中非極大值抑制的一段**(可以略過):
[cpp]view plain
copy
?/*
fucntion: non-maximum suppression
input:
pmag: pointer to magnitude,
pgradx: gradient of x-direction
pgrady: gradient of y-direction
sz: size of pmag (width = size.cx, height = size.cy)
output:
pnsrst: result of non-maximum suppression
*/
void
nonmaxsuppress(
int*pmag,
int* pgradx,
int*pgrady,size sz,
lpbyte
pnsrst)
for(y=0;y
for(y=1;y
else
//如果x,y兩個方向的方向導數方向相反
//c是當前畫素,與g1-g4的關係為:
// g2 g1
// c
// g3 g4
else
} else
//如果x,y兩個方向導數的方向相反
// c與g1-g4的關係為
// g1
// g4 c g2
// g3
else
} dtemp1 = weight*g1 + (1-weight)*g2;
dtemp2 = weight*g3 + (1-weight)*g4;
//當前畫素的梯度是區域性的最大值
//該點可能是邊界點
if(dtemp>=dtemp1 && dtemp>=dtemp2)
else
} }
} }
/*在上面**中,有幾個if-else需要注意。在john canny提出的canny運算元的**中,非最大值抑制就只是在0、90、45、135四個梯度方向上進行的,每個畫素點梯度方向按照相近程度用這四個方向來代替。這種情況下,非最大值抑制所比較的相鄰兩個畫素就是:fucntion: non-maximum suppression
input:
pmag: pointer to magnitude,
pgradx: gradient of x-direction
pgrady: gradient of y-direction
sz: size of pmag (width = size.cx, height = size.cy)
output:
pnsrst: result of non-maximum suppression
*/void nonmaxsuppress(int*pmag,int* pgradx,int*pgrady,size sz,lpbyte pnsrst)
for(y=0;y
for (y=1;y
else
//如果x,y兩個方向的方向導數方向相反
//c是當前畫素,與g1-g4的關係為:
// g2 g1
// c
// g3 g4
else
}else
//如果x,y兩個方向導數的方向相反
// c與g1-g4的關係為
// g1
// g4 c g2
// g3
else
}dtemp1 = weight*g1 + (1-weight)*g2;
dtemp2 = weight*g3 + (1-weight)*g4;
//當前畫素的梯度是區域性的最大值
//該點可能是邊界點
if(dtemp>=dtemp1 && dtemp>=dtemp2)
else}}
}}
1) 0:左邊 和 右邊
2)45:右上 和 左下
3)90: 上邊 和 下邊
4)135: 左上 和 右下
這樣做的好處是簡單, 但是這種簡化的方法無法達到最好的效果, 因為,自然影象中的邊緣梯度方向不一定是沿著這四個方向的。因此,就有很大的必要進行插值,找出在乙個畫素點上最能吻合其所在梯度方向的兩側的畫素值。
然而,實際數字影象中的畫素點是離散的二維矩陣,所以處在真正中心位置c處的梯度方向兩側的點是不一定存在的,或者說是乙個亞畫素(sub pixel)點,而這個不存在的點, 以及這個點的梯度值就必須通過對其兩側的點進行插值來得到。
對於上面的**,如果|gy|>|gx|,這說明該點的梯度方向更靠近y軸方向,所以g2和g4則在c的上下,我們可以用下面來說明這兩種情況(方向相同和方向不同):
上圖中,c表示中心位置點,斜的直線表示梯度方向(非極大值抑制是在梯度方向上的極大值),左邊的一副表示gy與gx的方向相同,而右邊的這幅這表示gy與gx的方向相反(注意原點在左上角),而權重則為weight = |gx|/|gy|,因此則根據此種情況,其插值表示則為:
[cpp]view plain
copy
?dtemp1 = weight*g1 + (1-weight)*g2;
dtemp2 = weight*g3 + (1-weight)*g4;
dtemp1 = weight*g1 + (1-weight)*g2;同理,我們可以得到|gx|>|gy|的情況,此時說明該點的梯度方向更靠近x軸方向,g2和g4則在水平方向,我們可以用下圖來說明該種情況:dtemp2 = weight*g3 + (1-weight)*g4;
上圖中,c表示中心位置點,斜的直線表示梯度方向(非極大值抑制是在梯度方向上的極大值),左邊的一副表示gy與gx的方向相同,而右邊的這幅這表示gy與gx的方向相反(注意原點在左上角),而權重則為weight = |gy|/|gx|,因此則根據此種情況,其插值表示則為:
[cpp]view plain
copy
?dtemp1 = weight*g1 + (1-weight)*g2;
dtemp2 = weight*g3 + (1-weight)*g4;
dtemp1 = weight*g1 + (1-weight)*g2;通過上面的分析,我們可以了解canny運算元中的非極大值抑制之前的準備工作,也即進行必要的插值。插值的原因再囉嗦下:①由於在canny運算元中採用的簡化方法來進行邊緣方向的確定,自然影象中邊緣梯度方向的不一定沿著該四個方向,因此為了找出在乙個畫素點上最能吻合其所在梯度方向的兩側的畫素值,就必須進行必要的插值;②也由於實際數字影象中的畫素點是離散的二維矩陣,處在真正中心位置c處的梯度方向兩側的點是不一定存在的,或者說是乙個亞畫素(sub pixel)點,而這個不存在的點, 以及這個點的梯度值就必須通過對其兩側的點進行插值來得到。dtemp2 = weight*g3 + (1-weight)*g4;
接下來的工作就比較簡單了,就是比較中心位置c處dtemp的梯度幅值與兩個插值點處的梯度幅值dtemp1和dtemp2的比較,確定是否為極值點,**如下:
[cpp]view plain
copy
print?if
(dtemp>=dtemp1 && dtemp>=dtemp2)
else
if(dtemp>=dtemp1 && dtemp>=dtemp2)到這裡,canny運算元的非極大值抑制部分就介紹完了。最後,需要說明的一點:canny運算元中的非極大值抑制與我們在角點檢測等場景中所說的非極大值抑制有點細微的差別。canny運算元中的非極大值抑制是沿著梯度方向進行的,即是否為梯度方向上的極值點;而在角點檢測等場景下說的非極大值抑制,則是檢測中心點處的值是否是某乙個鄰域內的最大值,是,則保留,否則去除,這種情況下的非極大值抑制比較簡單,如果不清楚可以參考:alexanderelse
neubeck的**:efficient non-maximum suppression。
非極大值抑制演算法
非極大值抑制演算法 non maximum suppression,nms 首次在 efficient non maximum suppression 被提出,多年之後被廣泛用於目標檢測領域,用於消除多餘的檢測框。目標檢測演算法 主流的有 rcnn 系 yolo 系 ssd 等 在進行目標檢測任務時...
非極大值抑制 非極大值抑制NMS的python實現
首先資料賦值和計算對應矩形框的面積 arr的資料格式是arr xmin,ymin,xmax,ymax,scores x1 arr 0 y1 arr 1 x2 arr 2 y2 arr 3 score arr 4 所有矩形框的面積 areas x2 x1 1 y2 y1 1 取出分數從大到小排列的索引...
非極大值抑制
nms non maximum suppression 中文名非極大值抑制,在很多計算機視覺任務中都有廣泛應用,如 邊緣檢測 目標檢測等。這裡主要以人臉檢測中的應用為例,來說明nms,並給出matlab和c 示例程式。人臉檢測的一些概念 1 絕大部分人臉檢測器的核心是分類器,即給定乙個尺寸固定,分類...