天天看點

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

1.3形态學圖像處理:膨脹與腐蝕

1.3.1理論與概念講解

<1>形态學概述

形态學(morphology)一詞通常表示生物學的一個分支,該分支主要研究動植物的形态和結構。而我們圖像進行中指的形态學,往往表示的是數學形态學。下面一起來了解數學形态學的概念。

數學形态學(Mathematical morphology) 是一門建立在格論和拓撲學基礎之上的圖像分析學科,是數學形态學圖像處理的基本理論。其基本的運算包括:二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形态學梯度、Top-hat變換、顆粒分析、流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形态學梯度等。

簡單來講,形态學操作就是基于形狀的一系列圖像處理操作。opencv為進行圖像的形态學變換提供了快捷、友善的函數。最基本的形态學操作有二種,他們是:膨脹與腐蝕(Dilation與Erosion)。

膨脹與腐蝕能實作多種多樣的功能,主要如下:

 消除噪聲;

 分割(isolate)出獨立的圖像元素,在圖像中連接配接(join)相鄰的元素;

 尋找圖像中的明顯的極大值區域或極小值區域;

 求出圖像的梯度。

我們在這裡給出下文會用到的,用于對比膨脹與腐蝕運算的“i”字樣毛筆字原圖:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖1

【注】圖檔來自OpenCV_Tutorials網站。

在進行腐蝕和膨脹的講解之前,首先需要注意,腐蝕和膨脹是對白色部分(高亮部分)而言的,不是黑色部分。膨脹就是圖像中的高亮部分進行膨脹,“領域擴張”,效果圖擁有比原圖更大的高亮區域。腐蝕就是原圖中的高亮部分被腐蝕,“領域被蠶食”,效果圖擁有比原圖更小的高亮區域。

<2>膨脹

其實,膨脹就是求局部最大值的操作。按數學方面來說,膨脹或者腐蝕操作就是将圖像(或圖像的一部分區域,我們稱之為A)與核(我們稱之為B)進行卷積。

核可以是任何的形狀和大小,它擁有一個單獨定義出來的參考點,我們稱其為錨點(anchorpoint)。多數情況下,核是一個小的中間帶有參考點和實心正方形或者圓盤,其實,我們可以把核視為模闆或者掩碼。

而膨脹就是求局部最大值的操作,核B與圖形卷積,即計算核B覆寫的區域的像素點的最大值,并把這個最大值指派給參考點指定的像素。這樣就會使圖像中的高亮區域逐漸增長。如下圖所示,這就是膨脹操作的初衷。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖2

膨脹的數學表達式:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

膨脹效果圖(毛筆字):

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖3 左圖像:原始圖像反向,右圖像: 原始圖像反向的膨脹圖像

<3>腐蝕

再來看一下腐蝕,大家應該知道,膨脹和腐蝕是一對好基友,是相反的一對操作,是以腐蝕就是求局部最小值的操作。

我們一般都會把腐蝕和膨脹對應起來了解和學習。下文就可以看到,兩者的函數原型也是基本上一樣的。

原理圖:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖4

腐蝕的數學表達式:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

腐蝕效果圖(毛筆字):

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖5左圖像:原始圖像反向,右圖像: 原始圖像反向造成的侵蝕

1.3.2 OpenCV源碼分析

/*【erode ( )函數源代碼】*************************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)  
 * @源碼路徑:…\opencv\sources\modules\imgproc\src\morph.cpp
 * @起始行數:1743行   
********************************************************************************/
void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
                Point anchor, int iterations,
                int borderType, const Scalar& borderValue )
{
//調用morphOp函數,并設定辨別符為MORPH_ERODE  
    morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}

/*【dilate( )函數源代碼】*************************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)  
 * @源碼路徑:…\opencv\sources\modules\imgproc\src\morph.cpp
 * @起始行數:1751行   
********************************************************************************/
void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
                 Point anchor, int iterations,
                 int borderType, const Scalar& borderValue )
{
//調用morphOp函數,并設定辨別符為MORPH_DILATE  
    morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
}
           

可以發現erode和dilate這兩個函數内部就是調用了一下morphOp,隻是他們調用morphOp時,第一個參數辨別符不同,一個為MORPH_ERODE(腐蝕),一個為MORPH_DILATE(膨脹)。

morphOp函數的源碼在… opencv\sources\modules\imgproc\src\morph.cpp中的第1677行,有興趣的朋友們可以研究研究,這裡就不費時費力花篇幅展開分析了。

【注】筆者分析的是3.0.0源碼,對于3.0版本以上的源碼大同小異,請讀者自行對比學習。

1.3.3 API函數講解

<1>形态學膨脹——dilate函數

erode函數,使用像素鄰域内的局部極大運算符來膨脹一張圖檔,從src輸入,由dst輸出。支援就地(in-place)操作。

C++: void dilate( InputArray src,  
                  OutputArray dst,  
                  InputArray kernel,  
                  Point anchor=Point(-1,-1),  
                  int iterations=1,  
                  int borderType=BORDER_CONSTANT,  
                  const Scalar& borderValue=morphologyDefaultBorderValue()   );             

【參數】

第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數量可以是任意的,但圖像深度應為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。

第二個參數,OutputArray類型的dst,即目标圖像,需要和源圖檔有一樣的尺寸和類型。

第三個參數,InputArray類型的kernel,膨脹操作的核。若為NULL時,表示的是使用參考點位于中心3x3的核。

我們一般使用函數 getStructuringElement配合這個參數的使用。getStructuringElement函數會傳回指定形狀和尺寸的結構元素(核心矩陣)。

其中,getStructuringElement函數的第一個參數表示核心的形狀,我們可以選擇如下三種形狀之一:

 矩形: MORPH_RECT

 交叉形: MORPH_CROSS

 橢圓形: MORPH_ELLIPSE

而getStructuringElement函數的第二和第三個參數分别是核心的尺寸以及錨點的位置。我們一般在調用erode以及dilate函數之前,先定義一個Mat類型的變量來獲得getStructuringElement函數的傳回值。對于錨點的位置,有預設值Point(-1,-1),表示錨點位于中心。且需要注意,十字形的element形狀唯一依賴于錨點的位置。而在其他情況下,錨點隻是影響了形态學運算結果的偏移。

getStructuringElement函數相關的調用示例代碼如下:

int g_nStructElementSize = 3; //結構元素(核心矩陣)的尺寸  
//擷取自定義核  
Mat element = getStructuringElement(MORPH_RECT,  
    Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),  
    Point( g_nStructElementSize, g_nStructElementSize ));             

調用這樣之後,我們便可以在接下來調用erode或dilate函數時,第三個參數填儲存了getStructuringElement傳回值的Mat類型變量。對應于我們上面的示例,就是填element變量。

第四個參數,Point類型的anchor,錨的位置,其有預設值(-1,-1),表示錨位于中心。

第五個參數,int類型的iterations,疊代使用erode()函數的次數,預設值為1。

第六個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有預設值BORDER_DEFAULT。

第七個參數,const Scalar&類型的borderValue,當邊界為常數時的邊界值,有預設值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數得到更詳細的解釋。

使用erode函數,一般我們隻需要填前面的三個參數,後面的四個參數都有預設值。而且往往結合getStructuringElement一起使用。

調用範例:

//載入原圖   
Mat image = imread("1.jpg");  
//擷取自定義核  
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));  
Mat out;  
//進行膨脹操作  
dilate(image, out, element);             

用上面核心代碼架起來的完整程式代碼。

參見附件【demo1】

運作截圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖6膨脹

<2>形态學腐蝕——erode函數

erode函數,使用像素鄰域内的局部極小運算符來腐蝕一張圖檔,從src輸入,由dst輸出。支援就地(in-place)操作。

C++: void erode(InputArray src,  
                OutputArray dst,  
                InputArray kernel,  
                Point anchor=Point(-1,-1),  
                int iterations=1,  
                int borderType=BORDER_CONSTANT,  
                const Scalar& borderValue=morphologyDefaultBorderValue()  
 );             

【參數】

第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像通道的數量可以是任意的,但圖像深度應為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。

第二個參數,OutputArray類型的dst,即目标圖像,需要和源圖檔有一樣的尺寸和類型。

第三個參數,InputArray類型的kernel,腐蝕操作的核心。若為NULL時,表示的是使用參考點位于中心3x3的核。我們一般使用函數 getStructuringElement配合這個參數的使用。getStructuringElement函數會傳回指定形狀和尺寸的結構元素(核心矩陣)。(具體看上文中淺出部分dilate函數的第三個參數講解部分)

第四個參數,Point類型的anchor,錨的位置,其有預設值(-1,-1),表示錨位于機關(element)的中心,我們一般不用管它。

第五個參數,int類型的iterations,疊代使用erode()函數的次數,預設值為1。

第六個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有預設值BORDER_DEFAULT。

第七個參數,const Scalar&類型的borderValue,當邊界為常數時的邊界值,有預設值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數得到更詳細的解釋。

同樣的,使用erode函數,一般我們隻需要填前面的三個參數,後面的四個參數都有預設值。而且往往結合getStructuringElement一起使用。

調用範例:

//載入原圖   
Mat image = imread("1.jpg");  
//擷取自定義核  
Mat element = getStructuringElement(MORPH_RECT, Size(15, 15));  
Mat out;  
//進行腐蝕操作  
 erode(image,out, element);             

用上面核心代碼架起來的完整程式代碼。

參見附件【demo2】

運作結果:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖7腐蝕操作

1.3.4膨脹與腐蝕綜合執行個體

這個示例程式中的效果圖視窗有兩個滾動條,顧名思義,第一個滾動條“腐蝕/膨脹”用于在腐蝕/膨脹之間進行切換;第二個滾動條”核心尺寸”用于調節形态學操作時的核心尺寸,以得到效果不同的圖像。

參見附件【demo3】

放出一些效果圖吧。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖8

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖9

參考連結:

英文:https://docs.opencv.org/master/db/df6/tutorial_erosion_dilatation.html

中文:

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html#morphology-1

1.4形态學圖像處理:開運算、閉運算、形态學梯度、頂帽、黑帽合輯

1.4.1理論與概念講解

首先呢,要知道形态學的進階形态,往往都是建立在腐蝕和膨脹這兩個基本操作之上的。而關于腐蝕和膨脹,概念和細節以及相關代碼可以看前文。對膨脹和腐蝕心中有數了,接下來的進階形态學操作,應該就不難了解。另外,為了下面對比和示範以及了解的友善,筆者自己制作了一張毛筆字圖,這裡先上原圖:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖10

<1>開運算(Opening Operation)

開運算(Opening Operation),其實就是先腐蝕後膨脹的過程。其數學表達式如下:

dst=open(src,element)=dilate(erode(src,element))

開運算可以用來消除小物體、在纖細點處分離物體、平滑較大物體的邊界的同時并不明顯改變其面積。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖11左圖像:原始圖像反向,右圖像: 原始圖像反向的開運算

<2>閉運算(Closing Operation)

先膨脹後腐蝕的過程稱為閉運算(Closing Operation),其數學表達式如下:

dst=close(src,element)=erode(dilate(src,element))

閉運算能夠排除小型黑洞(黑色區域)。效果圖如下所示:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖12左圖像:原始圖像反向,右圖像: 原始圖像反向的閉運算

<3>形态學梯度(MorphologicalGradient)

形态學梯度(Morphological Gradient)為膨脹圖與腐蝕圖之差,數學表達式如下:

dst=morphgrad(src,element)=dilate(src,element)−erode(src,element)

對二值圖像進行這一操作可以将團塊(blob)的邊緣突出出來。我們可以用形态學梯度來保留物體的邊緣輪廓,如下所示:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖13

<4>頂帽(Top Hat)

頂帽運算(Top Hat)又常常被譯為”禮帽“運算。為原圖像與上文剛剛介紹的“開運算“的結果圖之差,數學表達式如下:

dst=tophat(src,element)=src−open(src,element)

因為開運算帶來的結果是放大了裂縫或者局部低亮度的區域,是以,從原圖中減去開運算後的圖,得到的效果圖突出了比原圖輪廓周圍的區域更明亮的區域,且這一操作和選擇的核的大小相關。

頂帽運算往往用來分離比鄰近點亮一些的斑塊。當一幅圖像具有大幅的背景的時候,而微小物品比較有規律的情況下,可以使用頂帽運算進行背景提取。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖14

<5> 黑帽(Black Hat)

黑帽(Black Hat)運算為”閉運算“的結果圖與原圖像之差。數學表達式為:

dst=blackhat(src,element)=close(src,element)−src

黑帽運算後的效果圖突出了比原圖輪廓周圍的區域更暗的區域,且這一操作和選擇的核的大小相關。是以,黑帽運算用來分離比鄰近點暗一些的斑塊。非常完美的輪廓效果圖:

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖15

1.4.2 OpenCV源碼分析

本文的主角是OpenCV中的morphologyEx函數,它利用基本的膨脹和腐蝕技術,來執行更加進階的形态學變換,如開閉運算,形态學梯度,“頂帽”、“黑帽”等等。這一節我們來一起看一下morphologyEx函數的源代碼。

/*【morphologyEx ( )函數源代碼】******************************************************
 * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的對應版本源碼完全一樣,均在對應的安裝目錄下)  
 * @源碼路徑:…\opencv\sources\modules\imgproc\src\morph.cpp
 * @起始行數:1822行   
********************************************************************************/
void cv::morphologyEx( InputArray _src, OutputArray _dst, int op,
                       InputArray _kernel, Point anchor, int iterations,
                       int borderType, const Scalar& borderValue )
{
    Mat kernel = _kernel.getMat();
    if (kernel.empty())
    {
        kernel = getStructuringElement(MORPH_RECT, Size(3,3), Point(1,1));
    }
#ifdef HAVE_OPENCL
    Size ksize = kernel.size();
    anchor = normalizeAnchor(anchor, ksize);

    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && _src.channels() <= 4 &&
        anchor.x == ksize.width >> 1 && anchor.y == ksize.height >> 1 &&
        borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue(),
        ocl_morphologyEx(_src, _dst, op, kernel, anchor, iterations, borderType, borderValue))
#endif

    Mat src = _src.getMat(), temp; //拷貝Mat資料到臨時變量  
    _dst.create(src.size(), src.type());
    Mat dst = _dst.getMat();
//一個大switch,根據不同的辨別符取不同的操作  
    switch( op )
    {
    case MORPH_ERODE:
        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_DILATE:
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case MORPH_OPEN:
        erode( src, dst, kernel, anchor, iterations, borderType, borderValue );
        dilate( dst, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case CV_MOP_CLOSE:
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        erode( dst, dst, kernel, anchor, iterations, borderType, borderValue );
        break;
    case CV_MOP_GRADIENT:
        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
        dilate( src, dst, kernel, anchor, iterations, borderType, borderValue );
        dst -= temp;
        break;
    case CV_MOP_TOPHAT:
        if( src.data != dst.data )
            temp = dst;
        erode( src, temp, kernel, anchor, iterations, borderType, borderValue );
        dilate( temp, temp, kernel, anchor, iterations, borderType, borderValue );
        dst = src - temp;
        break;
    case CV_MOP_BLACKHAT:
        if( src.data != dst.data )
            temp = dst;
        dilate( src, temp, kernel, anchor, iterations, borderType, borderValue );
        erode( temp, temp, kernel, anchor, iterations, borderType, borderValue );
        dst = temp - src;
        break;
    default:
        CV_Error( CV_StsBadArg, "unknown morphological operation" );
    }
}
           

看上面的源碼可以發現,其實morphologyEx函數其實就是内部一個大switch而已。根據不同的辨別符取不同的操作。比如開運算MORPH_OPEN,按我們上文中講解的數學表達式,就是先腐蝕後膨脹,即依次調用erode和dilate函數,為非常簡明幹淨的代碼。

【注】筆者分析的是2.4.9源碼,對于3.0版本以上的源碼大同小異,請讀者自行對比學習。

1.4.3 API函數講解

<1> morphologyEx函數詳解

上面我們已經講到,morphologyEx函數利用基本的膨脹和腐蝕技術,來執行更加進階形态學變換,如開閉運算,形态學梯度,“頂帽”、“黑帽”等等。這一節我們來了解它的參數意義和使用方法。

C++: void morphologyEx( InputArray src,  
                        OutputArray   dst,  
                        int op,  
                        InputArray kernel,  
                        Pointanchor=Point(-1,-1),  
                        int iterations=1,  
                        int borderType=BORDER_CONSTANT,  
                        constScalar& borderValue=morphologyDefaultBorderValue() );             

【參數】

第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像位深應該為以下五種之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。

第二個參數,OutputArray類型的dst,即目标圖像,函數的輸出參數,需要和源圖檔有一樣的尺寸和類型。

第三個參數,int類型的op,表示形态學運算的類型,可以是如下之一的辨別符:

 MORPH_OPEN – 開運算(Opening operation)

 MORPH_CLOSE – 閉運算(Closing operation)

 MORPH_GRADIENT -形态學梯度(Morphological gradient)

 MORPH_TOPHAT - “頂帽”(“Top hat”)

 MORPH_BLACKHAT - “黑帽”(“Black hat“)

另有CV版本的辨別符也可選擇,如CV_MOP_CLOSE,CV_MOP_GRADIENT,CV_MOP_TOPHAT,CV_MOP_BLACKHAT,這應該是OpenCV1.0系列版本遺留下來的辨別符,和上面的“MORPH_OPEN”一樣的效果。

第四個參數,InputArray類型的kernel,形态學運算的核心。若為NULL時,表示的是使用參考點位于中心3x3的核。我們一般使用函數 getStructuringElement配合這個參數的使用。getStructuringElement函數會傳回指定形狀和尺寸的結構元素(核心矩陣)。關于getStructuringElement我們上篇文章中講過了,這裡為了大家參閱友善,再寫一遍:

其中,getStructuringElement函數的第一個參數表示核心的形狀,我們可以選擇如下三種形狀之一:

 矩形: MORPH_RECT

 交叉形: MORPH_CROSS

 橢圓形: MORPH_ELLIPSE

而getStructuringElement函數的第二和第三個參數分别是核心的尺寸以及錨點的位置。

我們一般在調用erode以及dilate函數之前,先定義一個Mat類型的變量來獲得getStructuringElement函數的傳回值。對于錨點的位置,有預設值Point(-1,-1),表示錨點位于中心。且需要注意,十字形的element形狀唯一依賴于錨點的位置。而在其他情況下,錨點隻是影響了形态學運算結果的偏移。

getStructuringElement函數相關的調用示例代碼如下:

int g_nStructElementSize = 3; //結構元素(核心矩陣)的尺寸  
//擷取自定義核  
Mat element =getStructuringElement(MORPH_RECT,  
       Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1),  
       Point(g_nStructElementSize, g_nStructElementSize ));             

調用這樣之後,我們便可以在接下來調用erode、dilate或morphologyEx函數時,kernel參數填儲存getStructuringElement傳回值的Mat類型變量。對應于我們上面的示例,就是填element變量。

第五個參數,Point類型的anchor,錨的位置,其有預設值(-1,-1),表示錨位于中心。

第六個參數,int類型的iterations,疊代使用函數的次數,預設值為1。

第七個參數,int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有預設值BORDER_ CONSTANT。

第八個參數,const Scalar&類型的borderValue,當邊界為常數時的邊界值,有預設值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時,可以看官方文檔中的createMorphologyFilter()函數得到更詳細的解釋。

其中的這些操作都可以進行就地(in-place)操作。且對于多通道圖像,每一個通道都是單獨進行操作。 OK,講解完畢,下面就是使用的範例。

為了友善大家需要的時候随時取用。下面我們依次列舉出開運算,閉運算,形态學梯度,頂帽,黑帽,腐蝕,膨脹的效果實作簡化版完整代碼。其實說白了,這些代碼基本上内容一緻,其實就是改一下morphologyEx裡面的第三個辨別符參數而已。核都是選的MORPH_RECT,矩形元素結構。另外,通過看源碼我們發現,最基本的腐蝕和膨脹操作也可以用morphologyEx函數來實作,他們由morphologyEx函數源碼中switch的前兩個case來實作(雖然在case體内就是簡單地各自調用了一下erode和dilation函數,但還是有寫出來的必要)。是以在這裡,我們也用morphologyEx再重新來實作一遍他們。

按着順序來列出吧,就直接列詳細注釋好的代碼和運作結果了。

<2>開運算示例程式

OpenCV中調用morphologyEx函數進行開運算操作的示例程式如下:

參考附件【demo4】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖16

<3>閉運算示例程式

OpenCV中調用morphologyEx函數進行閉運算操作的示例程式如下。

參見附件【demo5】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖17

<4>形态學梯度示例程式

OpenCV中調用morphologyEx函數進行形态學梯度操作的示例程式如下。

參見附件【demo6】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖18

<5>頂帽運算(Top Hat)示例程式

OpenCV中調用morphologyEx函數進行頂帽運算操作的示例程式如下。

參見附件【demo7】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖19

<6>黑帽運算(BlackHat)示例程式

OpenCV中調用morphologyEx函數進行黑帽運算操作的示例程式如下:

參見附件【demo8】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖20

<7>腐蝕(morphologyEx調用版)示例程式

OpenCV中調用morphologyEx函數進行腐蝕操作的示例程式如下。

參見附件【demo9】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖21

<8>膨脹(morphologyEx調用版)示例程式

OpenCV中調用morphologyEx函數進行膨脹操作的示例程式如下。

參見附件【demo10】,運作效果圖。

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖22

1.4.4形态學濾波綜合執行個體

這個示例程式中,一共有四個顯示圖像的視窗。原始圖一個,開/閉運算為一個,腐蝕/膨脹為一個,頂帽/黑帽運算為一個。分别使用滾動條,來控制得到的形态學效果。且疊代值為10的時候,為中間。另外,還可以通過鍵盤按鍵1,2,3以及空格,來調節成不同的元素結構(矩形、橢圓、十字形)。

參看附件【demo11】

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖23腐蝕/膨脹效果圖

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖24開/閉運算效果圖

【第二部分 圖像處理】第3章 Opencv圖像處理進階-【1 圖像處理B-形态學處理】(imgproc元件、feature2D元件)

圖25頂帽/黑帽運算效果圖

有沒有感覺很酷呢,繼續跟着部落客繼續學習吧,你會發現不一樣的驚奇喲!

參考連結:

本章附件:

繼續閱讀