OpenCV(六)形态学操作1--基础:膨胀与腐蚀(回调函数)
目錄
形態學通用API:morphologyEx
一、基礎理論
1、鄰接關系
(1)四鄰接:??????
(2)D鄰接:
(3) 八鄰接:
2、連通性
(1)四連通:
(2)八連通:
(3)m連通:
3、形態學基礎?
二、結構元?
三、膨脹
1、基礎理論
作用:
原理:
2、膨脹函數dilate()
3、代碼
4、效果
四、腐蝕
1、原理?
作用:
原理:
2、腐蝕函數erode()
?3、代碼、
4、效果
四、簡便操作---回調函數與滑動條
?1、回調函數
?2、滑動條創建
?3、代碼
4、效果
參考資料
形態學通用API:morphologyEx
morphologyEx(Mat src, Mat dst, int op, Mat kernel, Point anchor, int iterations, int borderType, Scalar borderValue)
參數介紹:
第一個參數,InputArray類型的src,輸入圖像,即源圖像,填Mat類的對象即可。圖像位深應該為以下五種之一:CV_8U, CV_16U,CV_16S, CV_32F 或CV_64F。
第二個參數,OutputArray類型的dst,即目標圖像,函數的輸出參數,需要和源圖片有一樣的尺寸和類型。
第三個參數,int類型的op,表示形態學運算的類型,可以是如下之一的標識符: ?enum MorphTypes{MORPH_ERODE = 0, //腐蝕MORPH_DILATE = 1, //膨脹MORPH_OPEN = 2, //開操作MORPH_CLOSE = 3, //閉操作MORPH_GRADIENT = 4, //梯度操作MORPH_TOPHAT = 5, //頂帽操作MORPH_BLACKHAT = 6, //黑帽操作MORPH_HITMISS = 7 };第四個參數,InputArray類型的kernel,形態學運算的內核。
一、基礎理論
1、鄰接關系
在圖像中,最小的單位是像素,每個像素周圍有8個鄰接像素,常見的鄰接關系有3種:4鄰接、D鄰接和8鄰接。
(1)四鄰接:??????
上下左右的點??
(2)D鄰接:
對角線的點
(3) 八鄰接:
四周的點
2、連通性
(1)四連通:
兩點在4鄰域范圍內。
(2)八連通:
兩點在8鄰域范圍內,
(3)m連通:
p/q在彼此的D鄰域內(4鄰域交集為空)
3、形態學基礎?
形態學是基于圖像形狀的一些操作,通常在二進制圖像上進行。(腐蝕和膨脹是兩個基本的形態學運算符, 它的變體形式如開運算、閉運算、禮帽和黑帽等等)
腐蝕和膨脹:
膨脹︰求局部最大值(消除內部噪聲)
腐蝕:求局部最小值(使內部噪聲變大)開閉運算:
開∶先腐蝕后膨脹(消除噪聲)閉:先膨脹后腐蝕(填充孔洞)
禮帽和黑帽:
禮帽:原圖像與開運算之差(找到亮區域)黑帽:閉運算與原圖像之差(找到暗區域)
二、結構元?
getStructuringElement()函數會返回指定形狀和尺寸的結構元素。
Mat getStructuringElement(int shape, Size esize, Point anchor = Point(-1, -1));參數介紹:
參數1:(卷積核形狀)
????????????????矩形:MORPH_RECT;
??????????????交叉形:MORPH_CROSS;
??????????????橢圓形:MORPH_ELLIPSE;
參數2:內核的尺寸(寬,高)(必須為奇數)
參數3:錨點位置(默認值Point(-1,-1)表示錨點位于中心點)
實例:
C++;
//卷積核(結構元)Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11) , Point(-1,-1));// 返回指定形狀和尺寸的結構元素 形狀 尺寸(寬, 高) 錨點(中心點)
三、膨脹
1、基礎理論
作用:
將與物體接觸的所有背景點融入物體中,使目標增大,可填補目標中的空洞。
原理:
取結構元領域內最大值,所以膨脹后輸出圖像的總體亮度的平均值比起原圖會有所升高,擴張高亮區域,而較暗物體的尺寸會減小甚至消失(暗的地方被覆蓋)。(紅色是參考點/錨點)(類似于“或”操作,附近都為0,錨點才為0,否則為1)
2、膨脹函數dilate()
c++:
//膨脹函數
dilate(img, dst, structureElement, Point(-1, -1), 1);
// 原圖 新圖 卷積核(結構元) 錨點 膨脹操作次數(默認1次)
?python:
dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)# 卷積核大小 迭代次數
3、代碼
C++:
//膨脹
void Dilate()
{//卷積核(結構元)Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11) , Point(-1,-1));// 返回指定形狀和尺寸的結構元素 形狀 尺寸(寬, 高) 錨點(中心點)//膨脹函數dilate(img, dst, structureElement, Point(-1, -1), 1);// 原圖 新圖 卷積核(結構元) 錨點 膨脹操作次數(默認1次)
}
python:
# 膨脹
def Dilate():# 膨脹dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)# 卷積核大小 迭代次數cv2.imshow("dilate", dilate)
4、效果
??
四、腐蝕
1、原理?
作用:
可以用于去除噪聲。?
原理:
腐蝕操作與膨脹操作類似,只是它取結構元所指定的領域內值的最小值作為該位置的輸出灰度值。因為取每個位置領域內最小值,所以腐蝕后輸出圖像的總體亮度的平均值比起原圖會有所降低,圖像中比較亮的區域的面積會變小甚至消失(亮的地方被覆蓋),而較暗區域的尺寸會擴大。(蠶食高亮區域)
(類似于“與”操作,附近只要有1個為0,錨點就位0)
2、腐蝕函數erode()
//腐蝕函數erode(img, dst, structureElement, Point(-1, -1), 1);// 原圖 新圖 卷積核(結構元) 錨點 腐蝕操作次數(默認1次)
erode = cv2.erode(img, kernel=(7, 7), iterations=5)# 卷積核大小 迭代次數
?3、代碼、
C++:
//腐蝕
void Erode()
{//卷積核(結構元)Mat structureElement = getStructuringElement(MORPH_RECT, Size(11, 11), Point(-1, -1));// 返回指定形狀和尺寸的結構元素 形狀 尺寸(寬, 高) 錨點(中心點)//腐蝕函數erode(img, dst, structureElement, Point(-1, -1), 1);// 原圖 新圖 卷積核(結構元) 錨點 腐蝕操作次數(默認1次)
}
python:?
# 腐蝕
def Enrode():# 腐蝕erode = cv2.erode(img, kernel=(7, 7), iterations=5)# 卷積核大小 迭代次數cv2.imshow("erode", erode)
4、效果
四、簡便操作---回調函數與滑動條
?1、回調函數
回調函數:把函數指針作為參數。
//回調函數膨脹
void CallBack_Dilate(int, void*)
// 軌跡條位置 用戶數據
{cont = element_size * 2 + 1; //結構元尺寸控制Dilate(); //膨脹imshow("Dilate:", dst); //顯示
}//回調函數腐蝕
void CallBack_Erode(int, void*)
// 軌跡條位置 用戶數據
{cont = element_size * 2 + 1; //結構元尺寸控制Erode(); //腐蝕imshow("Erode:", dst); //顯示
}
?2、滑動條創建
createTrackbar(conststring& trackbarname, conststring& winname, int* value, int count, TrackbarCallback onChange=0,void* userdata=0);?
參數解釋:?
1、trackbarname,表示軌跡條的名字,用來代表我們創建的軌跡條。
2、winname,填窗口的名字,表示這個軌跡條會依附到哪個窗口上,即對應namedWindow()創建窗口時填的某一個窗口名。(窗口名需與顯示窗口一致)
3、value,一個指向整型的指針,表示滑塊的位置。并且在創建時,滑塊的初始位置就是該變量當前的值。
4、count,表示滑塊可以達到的最大位置的值。滑塊最小的位置的值始終為0。
5、onChange,首先注意他有默認值0。這是一個指向回調函數的指針,每次滑塊位置改變時,這個函數都會進行回調。并且這個函數的原型必須為void XXXX(int,void*);其中第一個參數是軌跡條的位置,第二個參數是用戶數據(看下面的參數)。如果回調是NULL指針,表示沒有回調函數的調用,僅第三個參數value有變化。
6、userdata,他也有默認值0。這個參數是用戶傳給回調函數的數據,用來處理軌跡條事件。如果使用的第三個參數value實參是全局變量的話,完全可以不去管這個userdata參數。
//創建滑動條1(膨脹)
createTrackbar("結構元尺寸", "Dilate:", &element_size, max_size, CallBack_Dilate);
//創建滑動條2(腐蝕)
createTrackbar("結構元尺寸", "Erode:", &element_size, max_size, CallBack_Erode);
// 滑動條名字 窗口名字(必須和原窗口一致) 當前數值 最大數值 回調函數(函數指針作為參數)
//每次滑塊位置改變,回調函數都會回調
?3、代碼
C++:
//膨脹與腐蝕(回調函數)
#include <iostream>
#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;Mat img, dst;
int element_size = 3; //結構元大小(2*ele +1)
int max_size = 21; //最大容量
int cont; //控制結構元大小//圖像初始化
void Image_Init()
{img = imread("Resource/test4.jpg");dst = Mat::zeros(img.size(), img.type());if (img.empty()){printf("圖像加載失敗");exit(0);}
}//顯示圖像
void Show()
{imshow("原圖", img);
}//膨脹
void Dilate()
{//卷積核(結構元)Mat structureElement = getStructuringElement(MORPH_RECT, Size(cont, cont), Point(-1, -1));// 返回指定形狀和尺寸的結構元素 形狀 尺寸(寬, 高) 錨點(中心點)//膨脹函數dilate(img, dst, structureElement, Point(-1, -1), 1);// 原圖 新圖 卷積核(結構元) 錨點 膨脹操作次數(默認1次)
}//腐蝕
void Erode()
{//卷積核(結構元)Mat structureElement = getStructuringElement(MORPH_RECT, Size(cont, cont), Point(-1, -1));// 返回指定形狀和尺寸的結構元素 形狀 尺寸(寬, 高) 錨點(中心點)//腐蝕函數erode(img, dst, structureElement, Point(-1, -1), 1);// 原圖 新圖 卷積核(結構元) 錨點 腐蝕操作次數(默認1次)
}//回調函數膨脹
void CallBack_Dilate(int, void*)
// 軌跡條位置 用戶數據
{cont = element_size * 2 + 1; //結構元尺寸控制Dilate(); //膨脹imshow("Dilate:", dst); //顯示
}//回調函數腐蝕
void CallBack_Erode(int, void*)
// 軌跡條位置 用戶數據
{cont = element_size * 2 + 1; //結構元尺寸控制Erode(); //腐蝕imshow("Erode:", dst); //顯示
}int main()
{Image_Init(); //圖像初始化//Dilate(); //膨脹//Erode(); //腐蝕//回調函數(簡便控制膨脹與腐蝕)CallBack_Dilate(element_size, 0); //先顯示圖片(膨脹回調函數)CallBack_Erode(element_size, 0); //先顯示圖片(腐蝕回調函數)// 軌跡條位置 用戶數據//創建滑動條1(膨脹)createTrackbar("結構元尺寸", "Dilate:", &element_size, max_size, CallBack_Dilate);//創建滑動條2(腐蝕)createTrackbar("結構元尺寸", "Erode:", &element_size, max_size, CallBack_Erode);// 滑動條名字 窗口名字(必須和原窗口一致) 當前數值 最大數值 回調函數(函數指針作為參數)//每次滑塊位置改變,回調函數都會回調Show(); //顯示原圖像waitKey(0);return 0;
}
python:
# 形態學(膨脹、腐蝕、開閉運算、頂帽與底帽)
import cv2# 膨脹
def Dilate():# 膨脹dilate = cv2.dilate(img, kernel=(7, 7), iterations=1)# 卷積核大小 迭代次數cv2.imshow("dilate", dilate)# 腐蝕
def Enrode():# 腐蝕erode = cv2.erode(img, kernel=(7, 7), iterations=5)# 卷積核大小 迭代次數cv2.imshow("erode", erode)# 開運算(先腐后膨)
def Open():open = cv2.morphologyEx(img, cv2.MORPH_OPEN, (7, 7), iterations=5)# 類型 卷積核大小 迭代次數cv2.imshow('open', open)# 閉運算(先膨后腐)
def Close():close = cv2.morphologyEx(img, cv2.MORPH_CLOSE, (7, 7), iterations=5)# 類型 卷積核大小 迭代次數cv2.imshow('close', close)# 頂帽(原-開)
def TopHat():tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, (7, 7), iterations=5)
# 類型 卷積核 迭代次數cv2.imshow('TopHat', tophat)# 底帽(原-閉)
def BlackHat():blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, (7, 7), iterations=5)
# 類型 卷積核 迭代次數cv2.imshow('BlackHat', blackhat)if __name__ == '__main__':# 讀取圖片img = cv2.imread("Resource/test5.jpg")cv2.imshow("img", img)Dilate() #膨脹Enrode() #腐蝕Open() #開運算Close() #閉運算TopHat() #頂帽運算BlackHat() #底帽運算cv2.waitKey(0)
4、效果
參考資料
https://blog.csdn.net/weixin_41695564/article/details/79928835
https://www.bilibili.com/video/BV1uy4y1p7BR?from=search&seid=4644291277982613292
總結
以上是生活随笔為你收集整理的OpenCV(六)形态学操作1--基础:膨胀与腐蚀(回调函数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV(五)绘制图形与文本
- 下一篇: 数据结构与算法(7-4)最短路径(迪杰斯