天天看點

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

形态學(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();
}      

腐蝕效果:

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

膨脹效果: