天天看點

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

說明

開運算:先腐蝕後膨脹的過程,可以用來消除小物體、在纖細點處分離物體、平滑較大物體的邊界的同時并不明顯改變其面積。

閉運算:先膨脹後腐蝕的過程,能夠排除小型黑洞(黑色區域)。

形态學梯度:膨脹圖與腐蝕圖之差,對二值圖像進行這一操作可以将團塊(blob)的邊緣突出出來。可以用形态學梯度來保留物體的邊緣輪廓。

頂帽:為原圖像開運算的結果圖之差,放大了裂縫或者局部低亮度的區域,突出了比原圖輪廓周圍的區域更明亮的區域,且這一操作和選擇的核的大小相關。頂帽運算往往用來分離比鄰近點亮一些的斑塊。當一幅圖像具有大幅的背景的時候,而微小物品比較有規律的情況下,可以使用頂帽運算進行背景提取。

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

離散傅裡葉變換

圖像高頻部分代表了圖像的細節、紋理資訊;低頻代表了圖像的輪廓資訊。

低通-》模糊

高通-》銳化

腐蝕和膨脹是針對白色部分(高亮部分)而言的。膨脹就是對圖像高亮部分進行“領域擴張”,效果圖擁有比原圖更大的高亮區域;腐蝕是原圖中的高亮區域被蠶食,效果圖擁有比原圖更小的高亮區域。

開運算:先腐蝕再膨脹,用來消除小物體

閉運算:先膨脹再腐蝕,用于排除小型黑洞

形态學梯度:就是膨脹圖與俯視圖之差,用于保留物體的邊緣輪廓。

頂帽:原圖像與開運算圖之差,用于分離比鄰近點亮一些的斑塊。

黑帽:閉運算與原圖像之差,用于分離比鄰近點暗一些的斑塊。

示例:

//-----------------------------------【頭檔案包含部分】---------------------------------------
//    描述:包含程式所依賴的頭檔案
//---------------------------------------------------------------------------------------------- 
#include "pch.h"
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

//-----------------------------------【命名空間聲明部分】--------------------------------------
//    描述:包含程式所使用的命名空間
//----------------------------------------------------------------------------------------------- 
using namespace std;
using namespace cv;


//-----------------------------------【全局變量聲明部分】--------------------------------------
//    描述:全局變量聲明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage, g_dstImage;//原始圖和效果圖
int g_nElementShape = MORPH_RECT;//元素結構的形狀

//變量接收的TrackBar位置參數
int g_nMaxIterationNum = 10;
int g_nOpenCloseNum = 0;
int g_nErodeDilateNum = 0;
int g_nTopBlackHatNum = 0;



//-----------------------------------【全局函數聲明部分】--------------------------------------
//    描述:全局函數聲明
//-----------------------------------------------------------------------------------------------
static void on_OpenClose(int, void*);//回調函數
static void on_ErodeDilate(int, void*);//回調函數
static void on_TopBlackHat(int, void*);//回調函數
static void ShowHelpText();//幫助文字顯示


//-----------------------------------【main( )函數】--------------------------------------------
//    描述:控制台應用程式的入口函數,我們的程式從這裡開始
//-----------------------------------------------------------------------------------------------
int main()
{
  //改變console字型顔色
  system("color 2F");

  ShowHelpText();

  //載入原圖
  g_srcImage = imread("1.jpg");//工程目錄下需要有一張名為1.jpg的素材圖
  if (!g_srcImage.data) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; }

  //顯示原始圖
  namedWindow("【原始圖】");
  imshow("【原始圖】", g_srcImage);

  //建立三個視窗
  namedWindow("【開運算/閉運算】", 1);
  namedWindow("【腐蝕/膨脹】", 1);
  namedWindow("【頂帽/黑帽】", 1);

  //參數指派
  g_nOpenCloseNum = 9;
  g_nErodeDilateNum = 9;
  g_nTopBlackHatNum = 2;

  //分别為三個視窗建立滾動條
  createTrackbar("疊代值", "【開運算/閉運算】", &g_nOpenCloseNum, g_nMaxIterationNum * 2 + 1, on_OpenClose);
  createTrackbar("疊代值", "【腐蝕/膨脹】", &g_nErodeDilateNum, g_nMaxIterationNum * 2 + 1, on_ErodeDilate);
  createTrackbar("疊代值", "【頂帽/黑帽】", &g_nTopBlackHatNum, g_nMaxIterationNum * 2 + 1, on_TopBlackHat);

  //輪詢擷取按鍵資訊
  while (1)
  {
    int c;

    //執行回調函數
    on_OpenClose(g_nOpenCloseNum, 0);
    on_ErodeDilate(g_nErodeDilateNum, 0);
    on_TopBlackHat(g_nTopBlackHatNum, 0);

    //擷取按鍵
    c = waitKey(0);

    //按下鍵盤按鍵Q或者ESC,程式退出
    if ((char)c == 'q' || (char)c == 27)
      break;
    //按下鍵盤按鍵1,使用橢圓(Elliptic)結構元素結構元素MORPH_ELLIPSE
    if ((char)c == 49)//鍵盤按鍵1的ASII碼為49
      g_nElementShape = MORPH_ELLIPSE;
    //按下鍵盤按鍵2,使用矩形(Rectangle)結構元素MORPH_RECT
    else if ((char)c == 50)//鍵盤按鍵2的ASII碼為50
      g_nElementShape = MORPH_RECT;
    //按下鍵盤按鍵3,使用十字形(Cross-shaped)結構元素MORPH_CROSS
    else if ((char)c == 51)//鍵盤按鍵3的ASII碼為51
      g_nElementShape = MORPH_CROSS;
    //按下鍵盤按鍵space,在矩形、橢圓、十字形結構元素中循環
    else if ((char)c == ' ')
      g_nElementShape = (g_nElementShape + 1) % 3;
  }

  return 0;
}


//-----------------------------------【on_OpenClose( )函數】----------------------------------
//    描述:【開運算/閉運算】視窗的回調函數
//-----------------------------------------------------------------------------------------------
static void on_OpenClose(int, void*)
{
  //偏移量的定義
  int offset = g_nOpenCloseNum - g_nMaxIterationNum;//偏移量
  int Absolute_offset = offset > 0 ? offset : -offset;//偏移量絕對值
  //自定義核
  Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
  //進行操作
  if (offset < 0)
    morphologyEx(g_srcImage, g_dstImage, CV_MOP_OPEN, element);
  else
    morphologyEx(g_srcImage, g_dstImage, CV_MOP_CLOSE, element);
  //顯示圖像
  imshow("【開運算/閉運算】", g_dstImage);
}


//-----------------------------------【on_ErodeDilate( )函數】----------------------------------
//    描述:【腐蝕/膨脹】視窗的回調函數
//-----------------------------------------------------------------------------------------------
static void on_ErodeDilate(int, void*)
{
  //偏移量的定義
  int offset = g_nErodeDilateNum - g_nMaxIterationNum;  //偏移量
  int Absolute_offset = offset > 0 ? offset : -offset;//偏移量絕對值
  //自定義核
  Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
  //進行操作
  if (offset < 0)
    erode(g_srcImage, g_dstImage, element);
  else
    dilate(g_srcImage, g_dstImage, element);
  //顯示圖像
  imshow("【腐蝕/膨脹】", g_dstImage);
}


//-----------------------------------【on_TopBlackHat( )函數】--------------------------------
//    描述:【頂帽運算/黑帽運算】視窗的回調函數
//----------------------------------------------------------------------------------------------
static void on_TopBlackHat(int, void*)
{
  //偏移量的定義
  int offset = g_nTopBlackHatNum - g_nMaxIterationNum;//偏移量
  int Absolute_offset = offset > 0 ? offset : -offset;//偏移量絕對值
  //自定義核
  Mat element = getStructuringElement(g_nElementShape, Size(Absolute_offset * 2 + 1, Absolute_offset * 2 + 1), Point(Absolute_offset, Absolute_offset));
  //進行操作
  if (offset < 0)
    morphologyEx(g_srcImage, g_dstImage, MORPH_TOPHAT, element);
  else
    morphologyEx(g_srcImage, g_dstImage, MORPH_BLACKHAT, element);
  //顯示圖像
  imshow("【頂帽/黑帽】", g_dstImage);
}

//-----------------------------------【ShowHelpText( )函數】----------------------------------
//    描述:輸出一些幫助資訊
//----------------------------------------------------------------------------------------------
static void ShowHelpText()
{
  //輸出一些幫助資訊
  printf("\n\n\n\t請調整滾動條觀察圖像效果~\n\n");
  printf("\n\n\t按鍵操作說明: \n\n"
    "\t\t鍵盤按鍵【ESC】或者【Q】- 退出程式\n"
    "\t\t鍵盤按鍵【1】- 使用橢圓(Elliptic)結構元素\n"
    "\t\t鍵盤按鍵【2】- 使用矩形(Rectangle )結構元素\n"
    "\t\t鍵盤按鍵【3】- 使用十字型(Cross-shaped)結構元素\n"
    "\t\t鍵盤按鍵【空格SPACE】- 在矩形、橢圓、十字形結構元素中循環\n"
  );
}      

結果:

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