形態學操做是指基於形狀的一系列圖像處理操做,包括膨脹,腐蝕,二值化,開運算,閉運算,頂帽算法,黑帽算法,形態學梯度等,最基本的形態學操做就是膨脹和腐蝕.算法
一.膨脹函數
首先須要明確一個概念,膨脹和腐蝕都是針對於圖像中較亮的區域而言的,膨脹就是亮的區域變多了,而腐蝕就是暗的區域變多了.blog
膨脹的功能主要有消除噪聲,分割出獨立的圖像元素,在圖像操做的時候,有時候須要對圖像中的某些形狀進行檢測,而這些形狀相互鏈接在一塊兒,很差分開檢測,膨脹就能切開這些形狀(很小的鏈接位置),或者圖像中有很小塊的黑斑,或許是相機上的影響,膨脹,也能消除這些小的黑斑get
膨脹的基本思路就是圖像與一個核函數進行卷積,並取出結果中的極大值做爲結果,使得圖像中的高亮區域增加.這個核的形狀,錨點均可以進行設置,OPENCV提供了API供咱們得到核.it
API:Mat getStructuringElement(int 內核形狀,Size 內核尺寸,Point 錨點位置)圖像處理
注:內核形狀能夠取方形MORPH_RECT,十字形MORPH_CROSS,橢圓形MORPH_ELLIPSEopencv
錨點位置默認值Point(-1,-1),取形狀的中心class
經過該API就能夠得到相應的計算核,接下來計算膨脹的函數爲基礎
API:void dilate(源圖像,目標圖像,膨脹核,錨點,int 迭代次數,int邊界模式,int 邊界爲常數時邊界值)gc
注:該API支持in_place(源圖像能夠作目的圖像參數,算法會修改源圖像內數據),迭代次數默認爲1
例子以下
Mat srcImage; //膨脹 const int g_dilateIterMax = 100;//迭代次數 int g_nDilateIterValue; const int g_dilateCoreMax = 100;//核大小 int g_nDilateCoreValue; Mat dilateImage; void OnDilateIterTrackbar(int pos,void* userData); void onDilateCoreSizeTrackBar(int pos,void* userData); int main(int argc,char* argv) { srcImage = imread("F:\\opencv\\OpenCVImage\\erode_dilate.jpg"); namedWindow("src image"); namedWindow("dilate image"); g_nDilateIterValue = 1; g_nDilateCoreValue = 5; createTrackbar("inter count", "dilate image", &g_nDilateIterValue, g_dilateIterMax,OnDilateIterTrackbar); createTrackbar("core size", "dilate image", &g_nDilateCoreValue, g_dilateCoreMax,onDilateCoreSizeTrackBar); OnDilateIterTrackbar(g_nDilateIterValue,0); moveWindow("src image", 0, 0); moveWindow("dilate image", srcImage.cols, 0); imshow("src image", srcImage); waitKey(0); return 0; } //調整迭代次數 void OnDilateIterTrackbar(int pos,void* userData) { if(pos == 0||g_nDilateCoreValue == 0) { imshow("dilate image", srcImage); } else { if(g_nDilateCoreValue%2 == 0) { g_nDilateCoreValue++; } Mat core = getStructuringElement(MORPH_RECT, Size(g_nDilateCoreValue,g_nDilateCoreValue)); dilate(srcImage, dilateImage, core,Point(-1,-1),g_nDilateIterValue); imshow("dilate image", dilateImage); } } //調整核大小 void onDilateCoreSizeTrackBar(int pos,void* userData) { if(pos == 0 || g_nDilateIterValue == 0) { imshow("dilate image", srcImage); } else { if(g_nDilateCoreValue%2 == 0) { g_nDilateCoreValue++; } Mat core = getStructuringElement(MORPH_RECT, Size(g_nDilateCoreValue,g_nDilateCoreValue)); dilate(srcImage, dilateImage, core,Point(-1,-1),g_nDilateIterValue); imshow("dilate image", dilateImage); } }
二.腐蝕
腐蝕與膨脹正好相反,是求局部最小值的操做,亮的地方會減小,黑的地方會增多,在圖像中鏈接接近的區域,消除高亮形成的噪聲
API: void erode(源,目的,核,錨點,迭代次數,邊緣類型,邊緣爲常數時邊界值);
注:腐蝕和膨脹API的形式一致
使用代碼
//腐蝕 Mat srcImage; const int g_erodeIterMax = 100; int g_nErodeIterValue; const int g_erodeCoreMax = 100; int g_nErodeCoreValue; Mat erodeImage; void OnErodeIterTrackbar(int pos,void* userData); void onErodeCoreSizeTrackBar(int pos,void* userData); int main(int argc,char* argv) { srcImage = imread("F:\\opencv\\OpenCVImage\\erode_dilate.jpg"); namedWindow("src image"); namedWindow("erode image"); g_nErodeIterValue = 1; g_nErodeCoreValue = 5; createTrackbar("inter count", "erode image", &g_nErodeIterValue, g_erodeIterMax,OnErodeIterTrackbar); createTrackbar("core size", "erode image", &g_nErodeCoreValue, g_erodeCoreMax,onErodeCoreSizeTrackBar); OnErodeIterTrackbar(g_nErodeIterValue, 0); moveWindow("src image", 0, 0); moveWindow("erode image", srcImage.cols, 0); imshow("src image", srcImage); waitKey(0); return 0; } //調整迭代次數 void OnErodeIterTrackbar(int pos,void* userData) { if(pos == 0 || g_nErodeCoreValue == 0) { imshow("erode image", srcImage); } else { if(g_nErodeCoreValue%2 == 0) { g_nErodeCoreValue++; } Mat core = getStructuringElement(MORPH_RECT, Size(g_nErodeCoreValue,g_nErodeCoreValue),Point(-1,-1)); erode(srcImage, erodeImage, core,Point(-1,-1),g_nErodeIterValue); imshow("erode image", erodeImage); } } //調整核大小 void onErodeCoreSizeTrackBar(int pos,void* userData) { if(pos == 0 || g_nErodeIterValue == 0) { imshow("erode image", srcImage); } else { if(g_nErodeCoreValue%2 == 0) { g_nErodeCoreValue++; } Mat core = getStructuringElement(MORPH_RECT, Size(g_nErodeCoreValue,g_nErodeCoreValue),Point(-1,-1)); erode(srcImage, erodeImage, core,Point(-1,-1),g_nErodeIterValue); imshow("erode image", erodeImage); } }
三.形態學濾波算法
形態學的高級操做,每每都創建在基礎的膨脹和腐蝕的操做之上
1.開運算:開運算是一個先腐蝕,後膨脹的過程,用於在圖像中消除小的物體,在纖細點處分離物體,在平滑化較大的物體的邊界的同時不明顯改變物體的體積.
2.閉運算:先膨脹後腐蝕的過程,可以用於消除物體中的小型黑洞
3.形態學梯度:膨脹圖和腐蝕圖之差,對二值圖像進行這一操做,能夠將團塊的邊緣突出來,可使用形態學梯度來保留物體的邊緣輪廓.
4.頂帽:源圖像和開運算的結果的差值,每每用來分離比鄰近點亮一點的斑塊,在一幅圖具體大幅的背景,而微小物體有比較有規律的狀況下,可使用top_hat運算進行背景的提取
5.黑帽:閉運算的結果與源圖像之差,突出了比源圖像輪廓周圍更暗的區域,每每用於分離比鄰近點暗一些的斑塊.
核心API:void morpholgyEx(源,目標,int 形態學操做標誌,mat 形態學操做內核,Point 錨點,int 迭代次數,int 邊界模式,int 邊界爲常數時的邊界值).
注:形態學操做標誌的取值以下:MORPH_OPEN開運算 MORPH_CLOSE 閉運算 MORPH_GRENIENT 形態學梯度 MORPH_TOPHAT頂帽 MORPH_BLACKHAT黑帽 MORPH_ERODE腐蝕 MORPH_DILATE 膨脹
形態學操做內核就是前面膨脹腐蝕使用的內核.
使用範例以下:
1.開運算 閉運算 形態學梯度三者聯合
//源¡ä圖ª?像? Mat srcImage; //開a運?算? const int g_openIterMax = 100; int g_nopenIterValue; const int g_openCoreMax = 100; int g_nopenCoreValue; Mat openImage; void OnopenIterTrackbar(int pos,void* userData); void onopenCoreSizeTrackBar(int pos,void* userData); //閉À?運?算? const int g_closeIterMax = 100; int g_ncloseIterValue; const int g_closeCoreMax = 100; int g_ncloseCoreValue; Mat closeImage; void OncloseIterTrackbar(int pos,void* userData); void oncloseCoreSizeTrackBar(int pos,void* userData); //形?態¬?學¡ì梯¬Y度¨¨ const int g_gredientIterMax = 100; int g_ngredientIterValue; const int g_gredientCoreMax = 100; int g_ngredientCoreValue; Mat gredientImage; void OngredientIterTrackbar(int pos,void* userData); void ongredientCoreSizeTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\morpholgy.jpg"); g_nopenIterValue = 1; g_nopenCoreValue = 5; namedWindow("open image"); createTrackbar("iter count", "open image", &g_nopenIterValue, g_openIterMax,OnopenIterTrackbar,0); createTrackbar("core size", "open image", &g_nopenCoreValue, g_openCoreMax,onopenCoreSizeTrackBar,0); onopenCoreSizeTrackBar(g_nopenCoreValue, 0); g_ncloseCoreValue = 5; g_ncloseIterValue = 1; namedWindow("close image"); createTrackbar("iter count", "close image", &g_ncloseIterValue, g_closeIterMax,OncloseIterTrackbar,0); createTrackbar("core size", "close image", &g_ncloseCoreValue, g_closeCoreMax,oncloseCoreSizeTrackBar,0); oncloseCoreSizeTrackBar(g_ncloseCoreValue, 0); g_ngredientCoreValue = 5; g_ngredientIterValue = 1; namedWindow("gredient image"); createTrackbar("iter count", "gredient image", &g_ngredientIterValue, g_gredientIterMax,OngredientIterTrackbar,0); createTrackbar("core size", "gredient image", &g_ngredientCoreValue, g_gredientCoreMax,OngredientIterTrackbar,0); OngredientIterTrackbar(g_ngredientIterValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("open image", srcImage.cols, 0); moveWindow("close image", srcImage.cols*2, 0); moveWindow("gredient image", srcImage.cols*3, 0); waitKey(0); return 0; } void OnopenIterTrackbar(int pos,void* userData) { if(g_nopenCoreValue == 0||g_nopenIterValue == 0) { imshow("open image", srcImage); } else { if(g_nopenCoreValue%2 == 0) g_nopenCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_nopenCoreValue,g_nopenCoreValue)); morphologyEx(srcImage, openImage, MORPH_OPEN, core,Point(-1,-1),g_nopenIterValue); imshow("open image", openImage); } } void onopenCoreSizeTrackBar(int pos,void* userData) { if(g_nopenCoreValue == 0||g_nopenIterValue == 0) { imshow("open image", srcImage); } else { if(g_nopenCoreValue%2 == 0) g_nopenCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_nopenCoreValue,g_nopenCoreValue)); morphologyEx(srcImage, openImage, MORPH_OPEN, core,Point(-1,-1),g_nopenIterValue); imshow("open image", openImage); } } void OncloseIterTrackbar(int pos,void* userData) { if(g_ncloseCoreValue == 0||g_ncloseIterValue == 0) { imshow("close image", srcImage); } else { if(g_ncloseCoreValue%2 == 0) g_ncloseCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ncloseCoreValue,g_ncloseCoreValue)); morphologyEx(srcImage, closeImage, MORPH_CLOSE, core,Point(-1,-1),g_ncloseIterValue); imshow("close image", closeImage); } } void oncloseCoreSizeTrackBar(int pos,void* userData) { if(g_ncloseCoreValue == 0||g_ncloseIterValue == 0) { imshow("close image", srcImage); } else { if(g_ncloseCoreValue%2 == 0) g_ncloseCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ncloseCoreValue,g_ncloseCoreValue)); morphologyEx(srcImage, closeImage, MORPH_CLOSE, core,Point(-1,-1),g_ncloseIterValue); imshow("close image", closeImage); } } void OngredientIterTrackbar(int pos,void* userData) { if(g_ngredientCoreValue == 0||g_ngredientIterValue == 0) { imshow("gredient image", srcImage); } else { if(g_ngredientCoreValue%2 == 0) g_ngredientCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ngredientCoreValue,g_ngredientCoreValue)); morphologyEx(srcImage, gredientImage, MORPH_GRADIENT, core,Point(-1,-1),g_ngredientIterValue); imshow("gredient image", gredientImage); } } void ongredientCoreSizeTrackBar(int pos,void* userData) { if(g_ngredientCoreValue == 0||g_ngredientIterValue == 0) { imshow("gredient image", srcImage); } else { if(g_ngredientCoreValue%2 == 0) g_ngredientCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ngredientCoreValue,g_ngredientCoreValue)); morphologyEx(srcImage, gredientImage, MORPH_GRADIENT, core,Point(-1,-1),g_ngredientIterValue); imshow("gredient image", gredientImage); } }
2. 頂帽 黑帽結合
Mat srcImage; //頂£¤帽¡À tophat const int g_tophatIterMax = 100; int g_ntophatIterValue; const int g_tophatCoreMax = 100; int g_ntophatCoreValue; Mat tophatImage; void OntophatIterTrackbar(int pos,void* userData); void ontophatCoreSizeTrackBar(int pos,void* userData); //黑¨²帽¡À const int g_blackhatIterMax = 100; int g_nblackhatIterValue; const int g_blackhatCoreMax = 100; int g_nblackhatCoreValue; Mat blackhatImage; void OnblackhatIterTrackbar(int pos,void* userData); void onblackhatCoreSizeTrackBar(int pos,void* userData); int main(int argc,char* argv[]) { srcImage = imread("F:\\opencv\\OpenCVImage\\morpholgy.jpg"); g_ntophatIterValue = 1; g_ntophatCoreValue = 5; namedWindow("tophat image"); createTrackbar("iter count", "tophat image", &g_ntophatIterValue, g_tophatIterMax,OntophatIterTrackbar,0); createTrackbar("core size", "tophat image", &g_ntophatCoreValue, g_tophatCoreMax,ontophatCoreSizeTrackBar,0); ontophatCoreSizeTrackBar(g_ntophatCoreValue, 0); g_nblackhatCoreValue = 5; g_nblackhatIterValue = 1; namedWindow("blackhat image"); createTrackbar("iter count", "blackhat image", &g_nblackhatIterValue, g_blackhatIterMax,OnblackhatIterTrackbar,0); createTrackbar("core size", "blackhat image", &g_nblackhatCoreValue, g_blackhatCoreMax,onblackhatCoreSizeTrackBar,0); onblackhatCoreSizeTrackBar(g_nblackhatCoreValue, 0); imshow("src image", srcImage); moveWindow("src image", 0, 0); moveWindow("tophat image", srcImage.cols, 0); moveWindow("blackhat image", srcImage.cols*2, 0); waitKey(0); return 0; } void OntophatIterTrackbar(int pos,void* userData) { if(g_ntophatCoreValue == 0||g_ntophatIterValue == 0) { imshow("tophat image", srcImage); } else { if(g_ntophatCoreValue%2 == 0) g_ntophatCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ntophatCoreValue,g_ntophatCoreValue)); morphologyEx(srcImage, tophatImage, MORPH_TOPHAT, core,Point(-1,-1),g_ntophatIterValue); imshow("tophat image", tophatImage); } } void ontophatCoreSizeTrackBar(int pos,void* userData) { if(g_ntophatCoreValue == 0||g_ntophatIterValue == 0) { imshow("tophat image", srcImage); } else { if(g_ntophatCoreValue%2 == 0) g_ntophatCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_ntophatCoreValue,g_ntophatCoreValue)); morphologyEx(srcImage, tophatImage, MORPH_TOPHAT, core,Point(-1,-1),g_ntophatIterValue); imshow("tophat image", tophatImage); } } void OnblackhatIterTrackbar(int pos,void* userData) { if(g_nblackhatCoreValue == 0||g_nblackhatIterValue == 0) { imshow("blackhat image", srcImage); } else { if(g_nblackhatCoreValue%2 == 0) g_nblackhatCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_nblackhatCoreValue,g_nblackhatCoreValue)); morphologyEx(srcImage, blackhatImage, MORPH_BLACKHAT, core,Point(-1,-1),g_nblackhatIterValue); imshow("blackhat image", blackhatImage); } } void onblackhatCoreSizeTrackBar(int pos,void* userData) { if(g_nblackhatCoreValue == 0||g_nblackhatIterValue == 0) { imshow("blackhat image", srcImage); } else { if(g_nblackhatCoreValue%2 == 0) g_nblackhatCoreValue++; Mat core = getStructuringElement(MORPH_RECT, Size(g_nblackhatCoreValue,g_nblackhatCoreValue)); morphologyEx(srcImage, blackhatImage, MORPH_BLACKHAT, core,Point(-1,-1),g_nblackhatIterValue); imshow("blackhat image", blackhatImage); } }