1. 程式人生 > >canny運算元及邊緣提取原理

canny運算元及邊緣提取原理

在理解的過程中需要注意以下兩點:

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; } } } } }

以上程式碼來自我加了點註釋而已。