sobel算子原理及opencv源碼實現


sobel算子原理及opencv源碼實現

簡要描述

sobel算子主要用於獲得數字圖像的一階梯度,常見的應用和物理意義是邊緣檢測。

原理

算子使用兩個33的矩陣(圖1)算子使用兩個33的矩陣(圖1)去和原始圖片作卷積,分別得到橫向G(x)和縱向G(y)的梯度值,如果梯度值大於某一個閾值,則認為該點為邊緣點

                  sobel kernel
                           圖1:卷積矩陣

        sobel convolved
                            圖2:卷積運算  
                
事實上卷積矩陣也可以由兩個一維矩陣卷積而成,在opencv源碼中就是用兩個一維矩陣卷積生成一個卷積矩陣:

                  sobel two convolved
            
                     圖3:由兩個一維矩陣卷積生成的矩陣

static void getSobelKernels( OutputArray _kx, OutputArray _ky,
                         int dx, int dy, int _ksize, bool 	normalize, int ktype )
{
int i, j, ksizeX = _ksize, ksizeY = _ksize;
if( ksizeX == 1 && dx > 0 )
    ksizeX = 3;
if( ksizeY == 1 && dy > 0 )
    ksizeY = 3;

CV_Assert( ktype == CV_32F || ktype == CV_64F );

_kx.create(ksizeX, 1, ktype, -1, true);
_ky.create(ksizeY, 1, ktype, -1, true);
Mat kx = _kx.getMat();
Mat ky = _ky.getMat();

if( _ksize % 2 == 0 || _ksize > 31 )
    CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" );
std::vector<int> kerI(std::max(ksizeX, ksizeY) + 1);

CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );

for( int k = 0; k < 2; k++ )
{
    Mat* kernel = k == 0 ? &kx : &ky;
    int order = k == 0 ? dx : dy;
    int ksize = k == 0 ? ksizeX : ksizeY;

    CV_Assert( ksize > order );

    if( ksize == 1 )
        kerI[0] = 1;
    else if( ksize == 3 )
    {
        if( order == 0 )
            kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;
        else if( order == 1 )
            kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
        else
            kerI[0] = 1, kerI[1] = -2, kerI[2] = 1;
    }
    else
    {
        int oldval, newval;
        kerI[0] = 1;
        for( i = 0; i < ksize; i++ )
            kerI[i+1] = 0;

        for( i = 0; i < ksize - order - 1; i++ )
        {
            oldval = kerI[0];
            for( j = 1; j <= ksize; j++ )
            {
                newval = kerI[j]+kerI[j-1];
                kerI[j-1] = oldval;
                oldval = newval;
            }
        }

        for( i = 0; i < order; i++ )
        {
            oldval = -kerI[0];
            for( j = 1; j <= ksize; j++ )
            {
                newval = kerI[j-1] - kerI[j];
                kerI[j-1] = oldval;
                oldval = newval;
            }
        }
    }
    Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
    double scale = !normalize ? 1. : 1./(1 << (ksize-order-1));
    temp.convertTo(*kernel, ktype, scale);
}
}

}

從opencv源碼可以看出sobel的卷積矩陣在ksize==3時分別由[1,2,1]和[-1,0,1]生成。
圖像的梯度值由以下公式計算而來:
             sobel cacula

一般會用近似計算公式:

             sobel nearcacul

對於原始圖像4,p5的梯度值於:

             sobel near

                   sobel pic5

                     圖5 原始圖像


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM