OpenCV Sobel衍生物

2021-02-19 17:02 更新

目標(biāo)

在本教程中,您將學(xué)習(xí)如何:

  • 使用 OpenCV 函數(shù) ?cv :: Sobel? 來計(jì)算圖像中的衍生物。
  • 使用 OpenCV 函數(shù) ?cv :: Scharr? 計(jì)算 3 \ cdot 3 的內(nèi)核的更準(zhǔn)確的導(dǎo)數(shù) 3?3

理論

注意
下面的解釋屬于 Bradski 和 Kaehler 的《學(xué)習(xí) OpenCV 》一書。
  • 在最后兩個(gè)教程中,我們已經(jīng)看到了卷積的應(yīng)用例子。最重要的卷積之一是計(jì)算圖像中的導(dǎo)數(shù)(或與其近似)。
  • 為什么在圖像中派生物的演算可能很重要?讓我們想象一下,我們想要檢測(cè)圖像中存在的邊。例如:

Sobel衍生物

你可以很容易地注意到,在邊緣,像素強(qiáng)度以臭名昭著的方式發(fā)生變化。表達(dá)變化的一個(gè)好方法是使用衍生工具。梯度的高變化表示圖像的重大變化。

  • 為了更加圖形化,我們假設(shè)我們有一個(gè) 1D 圖像。在下面的圖中,邊緣以強(qiáng)度顯示為“跳躍”

Sobel衍生物

  • 如果我們采用一階導(dǎo)數(shù)(實(shí)際上,這里顯示為最大值),邊緣“跳”可以更容易看到

Sobel衍生物

  • 因此,從上面的解釋,我們可以推斷出,通過定位梯度高于鄰居的像素位置(或者概括為高于閾值),可以執(zhí)行檢測(cè)圖像邊緣的方法。
  • 更詳細(xì)的解釋,請(qǐng)參考 Bradski 和 Kaehler 學(xué)習(xí) OpenCV

Sobel 操作

  1. Sobel 運(yùn)算符是一個(gè)離散差分運(yùn)算符。它計(jì)算圖像強(qiáng)度函數(shù)的梯度的近似值。
  2. Sobel 算子結(jié)合高斯平滑和微分。

公式

假設(shè)要運(yùn)行的圖像是:I

  • 我們計(jì)算兩個(gè)派生詞:
  1. 水平變化:這是通過卷積計(jì)算與內(nèi)核具有奇數(shù)大小。例如,對(duì)于內(nèi)核大小為3,將計(jì)算為:IGxGx

Sobel衍生物

  1. 垂直變化:這是通過卷積計(jì)算與內(nèi)核具有奇數(shù)大小。例如,對(duì)于內(nèi)核大小為3,將被計(jì)算為: 一世 G? G?
  • 在圖像的每個(gè)點(diǎn),我們通過組合上述兩個(gè)結(jié)果來計(jì)算該點(diǎn)的漸變近似值:
Sobel衍生物

雖然有時(shí)使用以下簡單的方程:

Sobel衍生物

注意
當(dāng)內(nèi)核的大小是3,上面顯示的 Sobel 內(nèi)核可能會(huì)產(chǎn)生明顯的不準(zhǔn)確(畢竟 Sobel 只是導(dǎo)數(shù)的近似值)。OpenCV 通過使用cv :: Scharr函數(shù)解決了大小為 3 的內(nèi)核的不精確性。這與標(biāo)準(zhǔn)的 Sobel 功能一樣快,但更準(zhǔn)確。它實(shí)現(xiàn)以下內(nèi)核:

Sobel衍生物

您可以在 OpenCV 參考(?cv :: Scharr?)中查看此功能的更多信息。此外,在下面的示例代碼中,您會(huì)注意到,在 ?cv :: Sobel? 函數(shù)的代碼之上,還有一個(gè)注釋的?cv :: Scharr?函數(shù)的代碼。取消注釋(并且顯然評(píng)論 Sobel 的內(nèi)容)應(yīng)該給你一個(gè)這個(gè)功能如何工作的想法。

Code

  1. 這個(gè)程序是做什么的?應(yīng)用 Sobel 操作員,并生成作為輸出的圖像,檢測(cè)到的邊緣在較暗的背景上亮起。
  2. 教程代碼如下所示。您也可以從這里下載


#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;

int main( int argc, char** argv )
{
    Mat src, src_gray;
    Mat grad;
    const char* window_name = "Sobel Demo - Simple Edge Detector";
    int scale = 1;
    int delta = 0;
    int ddepth = CV_16S;
    String imageName("../data/lena.jpg"); 
    // 默認(rèn)情況下  
    if (argc > 1)
    {      
        imageName = argv[1];
    }  
    src = imread( imageName, IMREAD_COLOR ); 
    // 加載一張圖片  
    if( src.empty() )    
    {
        return -1;
    }  
    GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );  
    cvtColor( src, src_gray, COLOR_BGR2GRAY );  
    Mat grad_x, grad_y;
    Mat abs_grad_x, abs_grad_y;  
    //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );  
    Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); 
    //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );  
    Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );  
    convertScaleAbs( grad_x, abs_grad_x );  
    convertScaleAbs( grad_y, abs_grad_y );  
    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );  
    imshow( window_name, grad );  
    waitKey(0);  
    return 0;
}

說明

  • 首先我們聲明我們要使用的變量:
Mat src, src_gray;
Mat grad;
const char* window_name = "Sobel Demo - Simple Edge Detector";
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
  • 像往常一樣,我們加載我們的源圖像?src?
String imageName("../data/lena.jpg"); 
// 默認(rèn)情況下  
if (argc > 1)
{
    imageName = argv[1];
}
src = imread( imageName, IMREAD_COLOR ); 
// 加載一張圖片  
if( src.empty() )
{
    return -1;
}
  • 首先,我們將?cv :: GaussianBlur?應(yīng)用于我們的圖像以減少噪聲(內(nèi)核大小= 3)
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
  • 現(xiàn)在我們將過濾的圖像轉(zhuǎn)換為灰度:
cvtColor(src,src_gray,COLOR_BGR2GRAY);
  • 其次,我們?cè)?x 和 y 方向計(jì)算“*導(dǎo)數(shù)*” 。為此,我們使用函數(shù)?cv :: Sobel?,如下所示:
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;  
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );  
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );  
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );  
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );

該函數(shù)采用以下參數(shù):

  1. ?src_gray?:在我們的示例中,輸入圖像。這里是?CV_8U?;
  2. ?grad_x / * grad_y *?:輸出圖像;
  3. ?ddepth?:輸出圖像的深度。我們將其設(shè)置為?CV_16S?以避免溢出;
  4. ?x_order?:?x?方向上導(dǎo)數(shù)的順序;
  5. ?y_order?:?y?方向上導(dǎo)數(shù)的順序;
  6. ?scale?,?delta?和?BORDER_DEFAULT?:我們使用默認(rèn)值。

請(qǐng)注意,為了計(jì)算?x?方向的梯度,我們使用: 。我們以?y?方式做類似的事情。

  • 我們將部分結(jié)果轉(zhuǎn)換回?CV_8U?
convertScaleAbs(grad_x,abs_grad_x);
convertScaleAbs(grad_y,abs_grad_y);

最后,我們?cè)噲D接近梯度通過將兩個(gè)方向的梯度(注意,這是不是在所有的精確計(jì)算!但它有利于我們的目的)。

addWeighted(abs_grad_x,0.5,abs_grad_y,0.5,0,grad);

最后,我們展示我們的結(jié)果:

imshow(window_name,grad);
waitKey(0);

結(jié)果

這是將我們的基本檢測(cè)器應(yīng)用于?lena.jpg?的輸出:

Sobel衍生物


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)