OpenCV侵蝕和擴(kuò)張

2018-09-01 11:17 更新

目標(biāo)

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

  • 應(yīng)用兩個(gè)非常常見(jiàn)的形態(tài)運(yùn)算符:侵蝕和擴(kuò)張。為此,您將使用以下OpenCV功能:
注意
下面的解釋屬于Bradski和Kaehler 的“ 學(xué)習(xí)OpenCV ”一書(shū)。

形態(tài)作業(yè)

  • 簡(jiǎn)而言之:一組基于形狀處理圖像的操作。形態(tài)操作將結(jié)構(gòu)元素應(yīng)用于輸入圖像并生成輸出圖像。
  • 最基本的形態(tài)作用是:侵蝕和擴(kuò)張。它們有廣泛的用途,即:
  1. 消除噪音
  2. 隔離單個(gè)元素并連接圖像中的不同元素。
  3. 查找圖像中的強(qiáng)度凸點(diǎn)或孔
  • 我們將簡(jiǎn)要解釋膨脹和侵蝕,使用以下圖像作為示例:

OpenCV侵蝕和擴(kuò)張

擴(kuò)張

  • 該操作包括將圖像與某些內(nèi)核(B)進(jìn)行卷積,其可以具有任何形狀或尺寸,通常為正方形或圓形。AB
  • 內(nèi)核具有定義的錨點(diǎn),通常是內(nèi)核的中心。B
  • 當(dāng)內(nèi)核在圖像上掃描時(shí),我們計(jì)算由B重疊的最大像素值,并用該最大值替換錨點(diǎn)位置中的圖像像素。您可以推斷,這種最大化的操作會(huì)使圖像中的亮區(qū)“增長(zhǎng)”(因此稱為擴(kuò)張)。以上圖為例。應(yīng)用擴(kuò)張我們可以得到:BB

OpenCV擴(kuò)張

背景(明亮)擴(kuò)大了字母的黑色地區(qū)。

為了更好地把握想法并避免可能的混亂,在另一個(gè)例子中,我們已經(jīng)將原始圖像倒過(guò)來(lái),如白色的對(duì)象現(xiàn)在是這個(gè)字母。我們已經(jīng)執(zhí)行了兩個(gè)具有大小的矩形結(jié)構(gòu)元素的擴(kuò)張3x3。

OpenCV擴(kuò)張

左圖:原圖反轉(zhuǎn),右圖:產(chǎn)生擴(kuò)張

膨脹使物體變白。

侵蝕

  • 這個(gè)操作是擴(kuò)張的姊妹。它計(jì)算給定內(nèi)核區(qū)域的局部最小值。
  • 當(dāng)內(nèi)核在圖像上掃描時(shí),我們計(jì)算由重疊的最小像素值,并用該最小值替換錨點(diǎn)下的圖像像素。BB
  • 對(duì)于擴(kuò)張的例子,我們可以將侵蝕算子應(yīng)用于原始圖像(如上所示)。您可以在下面的結(jié)果中看到,圖像的明亮區(qū)域(背景,顯然)變得更薄,而黑暗區(qū)域(“寫(xiě)作”)變得更大。

OpenCV侵蝕

以相似的方式,通過(guò)對(duì)反轉(zhuǎn)的原始圖像(具有尺寸的矩形結(jié)構(gòu)元素的兩次侵蝕)施加侵蝕操作來(lái)產(chǎn)生相應(yīng)的圖像3x3:

OpenCV侵蝕

左圖:原圖反轉(zhuǎn),右圖:造成侵蝕

侵蝕使物體變白。

Code

本教程的代碼如下所示。您也可以在這里下載


#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
using namespace cv;
Mat src, erosion_dst, dilation_dst;
int erosion_elem = 0;
int erosion_size = 0;
int dilation_elem = 0;
int dilation_size = 0;
int const max_elem = 2;
int const max_kernel_size = 21;
void Erosion( int, void* );
void Dilation( int, void* );
int main( int, char** argv )
{
  src = imread( argv[1], IMREAD_COLOR );
  if( src.empty() )
    { return -1; }
  namedWindow( "Erosion Demo", WINDOW_AUTOSIZE );
  namedWindow( "Dilation Demo", WINDOW_AUTOSIZE );
  moveWindow( "Dilation Demo", src.cols, 0 );
  createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Erosion Demo",
          &erosion_elem, max_elem,
          Erosion );
  createTrackbar( "Kernel size:\n 2n +1", "Erosion Demo",
          &erosion_size, max_kernel_size,
          Erosion );
  createTrackbar( "Element:\n 0: Rect \n 1: Cross \n 2: Ellipse", "Dilation Demo",
          &dilation_elem, max_elem,
          Dilation );
  createTrackbar( "Kernel size:\n 2n +1", "Dilation Demo",
          &dilation_size, max_kernel_size,
          Dilation );
  Erosion( 0, 0 );
  Dilation( 0, 0 );
  waitKey(0);
  return 0;
}
void Erosion( int, void* )
{
  int erosion_type = 0;
  if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
  else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
  else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
  Mat element = getStructuringElement( erosion_type,
                       Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                       Point( erosion_size, erosion_size ) );
  erode( src, erosion_dst, element );
  imshow( "Erosion Demo", erosion_dst );
}
void Dilation( int, void* )
{
  int dilation_type = 0;
  if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
  else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
  else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
  Mat element = getStructuringElement( dilation_type,
                       Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                       Point( dilation_size, dilation_size ) );
  dilate( src, dilation_dst, element );
  imshow( "Dilation Demo", dilation_dst );
}

說(shuō)明

1、這里顯示的大部分材料是微不足道的(如果您有任何疑問(wèn),請(qǐng)參閱前幾節(jié)中的教程)。我們來(lái)看一下程序的一般結(jié)構(gòu):

  • 加載圖像(可以是BGR或灰度)
  • 創(chuàng)建兩個(gè)窗口(一個(gè)用于擴(kuò)張輸出,另一個(gè)用于侵蝕)
  • 為每個(gè)操作創(chuàng)建一組兩個(gè)Trackbars:

      a、第一個(gè)跟蹤欄 “元素”返回一個(gè)erosion_elem或dilation_ele

      b、第二個(gè)跟蹤欄 “內(nèi)核大小”返回對(duì)于相應(yīng)操作的erosion_size或dilation_size。

    • 每次我們移動(dòng)任何滑塊,用戶的功能Erosion或Dilation將被調(diào)用,它會(huì)根據(jù)當(dāng)前的跟蹤欄值來(lái)更新輸出圖像。

    我們分析這兩個(gè)功能:

    2、侵蝕:
    void Erosion( int, void* )
    {
      int erosion_type = 0;
      if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
      else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
      else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
      Mat element = getStructuringElement( erosion_type,
                           Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                           Point( erosion_size, erosion_size ) );
      erode( src, erosion_dst, element );
      imshow( "Erosion Demo", erosion_dst );
    }

    執(zhí)行侵蝕操作的功能是cv :: erode。我們可以看到,它有三個(gè)參數(shù):

    • src:源圖像
    • erosion_dst:輸出圖像
    • element:這是我們將用來(lái)執(zhí)行操作的內(nèi)核。如果我們不指定,默認(rèn)是一個(gè)簡(jiǎn)單的3x3矩陣。否則,我們可以指定它的形狀。為此,我們需要使用函數(shù)cv :: getStructuringElement
      Mat element = getStructuringElement( erosion_type,
                           Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                           Point( erosion_size, erosion_size ) );

    我們可以為我們的內(nèi)核選擇三種形狀:

    1. 矩形框:MORPH_RECT
    2. 十字架:MORPH_CROSS
    3. 橢圓:MORPH_ELLIPSE

    那么,我們只需要指定我們的內(nèi)核和錨點(diǎn)的大小。如果未指定,則假定為中心。

    • 就這些。我們準(zhǔn)備好對(duì)我們的形象進(jìn)行侵蝕。
    注意
    此外,還有一個(gè)參數(shù)允許您一次執(zhí)行多次侵蝕(迭代)。但是,我們沒(méi)有在這個(gè)簡(jiǎn)單的教程中使用它。您可以查閱參考資料了解更多詳情。

    3、擴(kuò)張:

    代碼如下。你可以看到,它完全類似于侵蝕代碼片段。這里我們還可以選擇定義我們的內(nèi)核,它的錨點(diǎn)和要使用的操作符的大小。

    
    void Dilation( int, void* )
    {
      int dilation_type = 0;
      if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
      else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
      else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
      Mat element = getStructuringElement( dilation_type,
                           Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                           Point( dilation_size, dilation_size ) );
      dilate( src, dilation_dst, element );
      imshow( "Dilation Demo", dilation_dst );
    }

    結(jié)果

    編譯上面的代碼,并以圖像作為參數(shù)執(zhí)行。例如,使用這個(gè)圖像:

    OpenCV侵蝕和擴(kuò)張

    我們得到以下結(jié)果。自然地,改變軌道欄中的索引給出不同的輸出圖像。試試吧!甚至可以嘗試添加第三個(gè)Trackbar來(lái)控制迭代次數(shù)。

    OpenCV侵蝕和擴(kuò)張


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

    掃描二維碼

    下載編程獅App

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

    編程獅公眾號(hào)