形態學影象處理:膨脹與腐蝕
形態學(morphology)一詞通常表示生物學的一個分支,該分支主要研究動植物的形態和結構。而我們影象處理中指的形態學,往往表示的是數學形態學。下面一起來了解數學形態學的概念。
數學形態學(Mathematical morphology) 是一門建立在格論和拓撲學基礎之上的影象分析學科,是數學形態學影象處理的基本理論。其基本的運算包括:二值腐蝕和膨脹、二值開閉運算、骨架抽取、極限腐蝕、擊中擊不中變換、形態學梯度、Top-hat變換、顆粒分析、流域變換、灰值腐蝕和膨脹、灰值開閉運算、灰值形態學梯度等。
簡單來講,形態學操作就是基於形狀的一系列影象處理操作。OpenCV為進行影象的形態學變換提供了快捷、方便的函式。最基本的形態學操作有二種,他們是:膨脹與腐蝕(Dilation與Erosion)。
膨脹與腐蝕能實現多種多樣的功能,主要如下:
- 消除噪聲
- 分割(isolate)出獨立的影象元素,在影象中連線(join)相鄰的元素。
- 尋找影象中的明顯的極大值區域或極小值區域
- 求出影象的梯度
腐蝕和膨脹是對白色部分(高亮部分)而言的,不是黑色部分。膨脹就是影象中的高亮部分進行膨脹,“領域擴張”,效果圖擁有比原圖更大的高亮區域。腐蝕就是原圖中的高亮部分被腐蝕,“領域被蠶食”,效果圖擁有比原圖更小的高亮區域。
膨脹就是求區域性最大值的操作。
按數學方面來說,膨脹或者腐蝕操作就是將影象(或影象的一部分割槽域,我們稱之為A)與核(我們稱之為B)進行卷積。
核可以是任何的形狀和大小,它擁有一個單獨定義出來的參考點,我們稱其為錨點(anchorpoint)。多數情況下,核是一個小的中間帶有參考點和實心正方形或者圓盤,其實,我們可以把核視為模板或者掩碼。
而膨脹就是求區域性最大值的操作,核B與圖形卷積,即計算核B覆蓋的區域的畫素點的最大值,並把這個最大值賦值給參考點指定的畫素。這樣就會使影象中的高亮區域逐漸增長。如下圖所示,這就是膨脹操作的初衷。
形態學膨脹用dilate函式,形態學腐蝕用erode函式。
示例:
//-----------------------------------【標頭檔案包含部分】---------------------------------------
// 描述:包含程式所依賴的標頭檔案
//----------------------------------------------------------------------------------------------
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include <iostream>
//-----------------------------------【名稱空間宣告部分】---------------------------------------
// 描述:包含程式所使用的名稱空間
//-----------------------------------------------------------------------------------------------
using namespace std;
using namespace cv;
//-----------------------------------【全域性變數宣告部分】--------------------------------------
// 描述:全域性變數宣告
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage;//原始圖和效果圖
int g_nTrackbarNumer = 0;//0表示腐蝕erode, 1表示膨脹dilate
int g_nStructElementSize = 3; //結構元素(核心矩陣)的尺寸
//-----------------------------------【全域性函式宣告部分】--------------------------------------
// 描述:全域性函式宣告
//-----------------------------------------------------------------------------------------------
void Process();//膨脹和腐蝕的處理函式
void on_TrackbarNumChange(int, void *);//回撥函式
void on_ElementSizeChange(int, void *);//回撥函式
//-----------------------------------【main( )函式】--------------------------------------------
// 描述:控制檯應用程式的入口函式,我們的程式從這裡開始
//-----------------------------------------------------------------------------------------------
int main()
{
//改變console字型顏色
system("color5E");
//載入原圖
g_srcImage = imread("1.jpg");
if (!g_srcImage.data) { printf("讀取srcImage錯誤\n"); return false; }
//顯示原始圖
namedWindow("【原始圖】");
imshow("【原始圖】", g_srcImage);
//進行初次腐蝕操作並顯示效果圖
namedWindow("【效果圖】");
//獲取自定義核
Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1), Point(g_nStructElementSize, g_nStructElementSize));
erode(g_srcImage, g_dstImage, element);
imshow("【效果圖】", g_dstImage);
//建立軌跡條
createTrackbar("腐蝕/膨脹", "【效果圖】", &g_nTrackbarNumer, 1, on_TrackbarNumChange);
createTrackbar("核心尺寸", "【效果圖】", &g_nStructElementSize, 21, on_ElementSizeChange);
//輸出一些幫助資訊
cout << endl << "\t執行成功,請調整滾動條觀察影象效果~\n\n"
<< "\t按下“q”鍵時,程式退出~!\n";
//輪詢獲取按鍵資訊,若下q鍵,程式退出
while (char(waitKey(1)) != 'q') {}
return 0;
}
//-----------------------------【Process( )函式】------------------------------------
// 描述:進行自定義的腐蝕和膨脹操作
//-----------------------------------------------------------------------------------------
void Process()
{
//獲取自定義核
Mat element = getStructuringElement(MORPH_RECT, Size(2 * g_nStructElementSize + 1, 2 * g_nStructElementSize + 1), Point(g_nStructElementSize, g_nStructElementSize));
//進行腐蝕或膨脹操作
if (g_nTrackbarNumer == 0) {
erode(g_srcImage, g_dstImage, element);
}
else {
dilate(g_srcImage, g_dstImage, element);
}
//顯示效果圖
imshow("【效果圖】", g_dstImage);
}
//-----------------------------【on_TrackbarNumChange( )函式】------------------------------------
// 描述:腐蝕和膨脹之間切換開關的回撥函式
//-----------------------------------------------------------------------------------------------------
void on_TrackbarNumChange(int, void *)
{
//腐蝕和膨脹之間效果已經切換,回撥函式體內需呼叫一次Process函式,使改變後的效果立即生效並顯示出來
Process();
}
//-----------------------------【on_ElementSizeChange( )函式】-------------------------------------
// 描述:腐蝕和膨脹操作核心改變時的回撥函式
//-----------------------------------------------------------------------------------------------------
void on_ElementSizeChange(int, void *)
{
//核心尺寸已改變,回撥函式體內需呼叫一次Process函式,使改變後的效果立即生效並顯示出來
Process();
}
腐蝕效果:
膨脹效果: