形态學(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();
}
腐蝕效果:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CNxcTNyMGZlF2Y4MmZ5czYyYzX2UDOwETM4AzLcdDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
膨脹效果: