canny運算元及邊緣提取原理
阿新 • • 發佈:2019-01-22
在理解的過程中需要注意以下兩點:
1.中非最大抑制是回答這樣一個問題:“當前的梯度值在梯度方向上是一個區域性最大值嗎?”所以,要把當前位置的梯度值與梯度方向上兩側的梯度值進行比較。
2.梯度方向垂直於邊緣方向。但實際上,我們只能得到C點鄰域的8個點的值,而dTmp1和dTmp2
並不在其中,要得到這兩個值就需要對dTmp1和dTmp2兩點進行線性插值,也即根據圖1中的g1和g2對dTmp1進行插值,根據g3和g4對dTmp2進行插值(以得到dTmp1、dTmp2兩個位置處的畫素值),這要用到其梯度方向,這也是Canny演算法中要求解梯度方向矩陣Thita的原因(演算法的第二步)。
完成非極大值抑制後,會得到一個二值影象,非邊緣的點灰度值均為0,可能為邊緣的區域性灰度極大值點可設定其灰度為128或者其他。
程式碼+註釋:
void NonMaxSuppress(int*pMag,int* pGradX,int*pGradY,SIZE sz,LPBYTE pNSRst) { LONG x,y; int nPos; // the component of the gradient int gx,gy; // the temp varialbe int g1,g2,g3,g4; double weight; double dTemp,dTemp1,dTemp2; //設定影象邊緣為不可能的分界點 for(x=0;x<sz.cx;x++) { pNSRst[x] = 0; pNSRst[(sz.cy-1)*sz.cx+x] = 0; } for(y=0;y<sz.cy;y++) { pNSRst[y*sz.cx] = 0; pNSRst[y*sz.cx + sz.cx-1] = 0; } for (y=1;y<sz.cy-1;y++) { for (x=1;x<sz.cx-1;x++) { nPos=y*sz.cx+x; // if pMag[nPos]==0, then nPos is not the edge point if (pMag[nPos]==0) { pNSRst[nPos]=0; } else { // the gradient of current point dTemp=pMag[nPos]; // x,y 方向導數 gx=pGradX[nPos]; gy=pGradY[nPos]; //如果方向導數y分量比x分量大,說明導數方向趨向於y分量,即更貼近y軸 if (abs(gy)>abs(gx)) { // calculate the factor of interplation weight=fabs(gx)/fabs(gy); g2 = pMag[nPos-sz.cx]; // 確定g2出現在c(中心點)的上一行 g4 = pMag[nPos+sz.cx]; // 確定g4出現在c(中心點)的下一行 //C 為當前畫素,與g1-g4 的位置關係為: //g1 g2 // C // g4 g3 if(gx*gy>0) //如果x,y兩個方向導數的符號相同 { g1 = pMag[nPos-sz.cx-1]; g3 = pMag[nPos+sz.cx+1]; } //對的,畫個圖可以很好的理解。 左上角為原點,x,y導數相同即導數線跨越2 4象限 如上圖1
//如果x,y兩個方向的方向導數方向相反 //C是當前畫素,與g1-g4的關係為: // g2 g1 // C // g3 g4 else //左上角為原點,x,y導數相反即導數線跨越1 3象限 如上圖2 { g1 = pMag[nPos-sz.cx+1]; g3 = pMag[nPos+sz.cx-1]; } } else { //插值比例 weight = fabs(gy)/fabs(gx); g2 = pMag[nPos+1]; //後一列 g4 = pMag[nPos-1]; // 前一列 //如果x,y兩個方向的方向導數符號相同 //當前畫素C與 g1-g4的關係為 // g3 // g4 C g2 // g1 if(gx * gy > 0) { g1 = pMag[nPos+sz.cx+1]; g3 = pMag[nPos-sz.cx-1]; } //如果x,y兩個方向導數的方向相反 // C與g1-g4的關係為 // g1 // g4 C g2 // g3 else { g1 = pMag[nPos-sz.cx+1]; g3 = pMag[nPos+sz.cx-1]; } } dTemp1 = weight*g1 + (1-weight)*g2; dTemp2 = weight*g3 + (1-weight)*g4; //當前畫素的梯度是區域性的最大值 //該點可能是邊界點 if(dTemp>=dTemp1 && dTemp>=dTemp2) { pNSRst[nPos] = 128; } else { //不可能是邊界點 pNSRst[nPos] = 0; } } } } }
以上程式碼來自我加了點註釋而已。