OpenCV圖像處理之實(shí)現(xiàn)圖像膨脹腐蝕操作
一.形態(tài)學(xué)操作概念
圖像形態(tài)學(xué)操作是指基于形狀的一系列圖像處理操作的合集,主要是基于集合論基礎(chǔ)上的形態(tài)學(xué)數(shù)學(xué)對(duì)圖像進(jìn)行處理。
形態(tài)學(xué)有四個(gè)基本操作:腐蝕、膨脹、開操作、閉操作,膨脹與腐蝕是圖像處理中最常用的形態(tài)學(xué)操作手段。
二.形態(tài)學(xué)操作-膨脹
跟卷積操作類似,假設(shè)有圖像A和結(jié)構(gòu)元素B,結(jié)構(gòu)元素B在圖像A上面移動(dòng),其中結(jié)構(gòu)元素B定義其中心為錨點(diǎn),計(jì)算B覆蓋下A的最大像素值用來替換錨點(diǎn)的像素,其中B作為結(jié)構(gòu)體可以是任意形狀。
膨脹的原理:
膨脹或者腐蝕操作就是將圖像(或圖像的一部分區(qū)域,我們稱之為圖像A)與結(jié)構(gòu)元素(我們稱之為卷積核B)進(jìn)行卷積。核可以是任何的形狀和大小,擁有一個(gè)單獨(dú)定義出來的參考點(diǎn),我們稱其為錨點(diǎn)(anchorpoin)。多數(shù)情況下,核是一個(gè)小的中間帶有參考點(diǎn)和實(shí)心正方形或者圓盤,可以把核視為模板或者掩碼。
膨脹就是求局部最大值的操作,核B與圖形卷積,即計(jì)算核B覆蓋的區(qū)域的像素點(diǎn)的最大值,并把這個(gè)最大值賦值給參考點(diǎn)指定的像素。這樣就會(huì)使圖像中的高亮區(qū)域逐漸增長。
膨脹和腐蝕操作的核心內(nèi)容是結(jié)構(gòu)元素。一般來說結(jié)構(gòu)元素是由元素為1或者0的矩陣組成。結(jié)構(gòu)元素為1的區(qū)域定義了圖像的領(lǐng)域,領(lǐng)域內(nèi)的像素在進(jìn)行膨脹和腐蝕等形態(tài)學(xué)操作時(shí)要進(jìn)行考慮。
膨脹函數(shù)API接口
dst=cv2.dilate( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() );
參數(shù)詳解:
第一個(gè)參數(shù),InputArray類型的src,輸入圖像,即源圖像,填Mat類的對(duì)象即可。圖像通道的數(shù)量可以是任意的,但圖像深度應(yīng)為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二個(gè)參數(shù),OutputArray類型的dst,即目標(biāo)圖像,需要和源圖片有一樣的尺寸和類型。
第三個(gè)參數(shù),InputArray類型的kernel,膨脹操作的核。若為NULL時(shí),表示的是使用參考點(diǎn)位于中心3x3的核。
我們一般使用函數(shù) getStructuringElement配合這個(gè)參數(shù)的使用。getStructuringElement函數(shù)會(huì)返回指定形狀和尺寸的結(jié)構(gòu)元素(內(nèi)核矩陣)。
其中,getStructuringElement函數(shù)的第一個(gè)參數(shù)表示內(nèi)核的形狀,我們可以選擇如下三種形狀之一:
- 矩形: MORPH_RECT
- 交叉形: MORPH_CROSS
- 橢圓形: MORPH_ELLIPSE
而getStructuringElement函數(shù)的第二和第三個(gè)參數(shù)分別是內(nèi)核的尺寸以及錨點(diǎn)的位置。
我們一般在調(diào)用erode以及dilate函數(shù)之前,先定義一個(gè)Mat類型的變量來獲得getStructuringElement函數(shù)的返回值。對(duì)于錨點(diǎn)的位置,有默認(rèn)值Point(-1,-1),表示錨點(diǎn)位于中心。且需要注意,十字形的element形狀唯一依賴于錨點(diǎn)的位置。而在其他情況下,錨點(diǎn)只是影響了形態(tài)學(xué)運(yùn)算結(jié)果的偏移。
getStructuringElement函數(shù)相關(guān)的調(diào)用示例代碼如下:
int g_nStructElementSize = 3; //結(jié)構(gòu)元素(內(nèi)核矩陣)的尺寸 //獲取自定義核 Mat element = getStructuringElement(MORPH_RECT, Size(2*g_nStructElementSize+1,2*g_nStructElementSize+1), Point( g_nStructElementSize, g_nStructElementSize ));
第四個(gè)參數(shù),Point類型的anchor,錨的位置,其有默認(rèn)值(-1,-1),表示錨位于中心。
第五個(gè)參數(shù),int類型的iterations,迭代使用erode()函數(shù)的次數(shù),默認(rèn)值為1。
第六個(gè)參數(shù),int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有默認(rèn)值BORDER_DEFAULT。
第七個(gè)參數(shù),const Scalar&類型的borderValue,當(dāng)邊界為常數(shù)時(shí)的邊界值,有默認(rèn)值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時(shí),可以看官方文檔中的createMorphologyFilter()函數(shù)得到更詳細(xì)的解釋。
使用erode函數(shù),一般我們只需要填前面的三個(gè)參數(shù),后面的四個(gè)參數(shù)都有默認(rèn)值。而且往往結(jié)合getStructuringElement一起使用。
結(jié)構(gòu)元素的API函數(shù)接口
cv::Mat kernel = getStructuringElement(int shape,Size ksize,Point anchor); //返回值:返回指定形狀和尺寸的結(jié)構(gòu)元素 //結(jié)構(gòu)元素的定義:形狀 (MORPH_RECT(矩形核) //MORPH_CROSS(十字交叉形核) //MORPH_ELLIPSE(橢圓形核));結(jié)構(gòu)元素大??;錨點(diǎn) 默認(rèn)是Point(-1, -1)意思就是中心像素,也可以自己指定 //函數(shù)接口示例 cv::Mat elementRect,elementCross,elementEllipse; elementRect = cv::getStructuringElement(cv::MORPH_RECT,cv::Size(3,3),cv::Point(-1,-1)); elementCross = cv::getStructuringElement(cv::MORPH_CROSS,cv::Size(3,3),cv::Point(-1,-1)); elementEllipse = cv::getStructuringElement(cv::MORPH_ELLIPSE,cv::Size(5,5),cv::Point(-1,-1));
此外,我們也可以自定義結(jié)構(gòu)元素,如下:
使用Mat_模板類自定義5×5大小十字形、菱形、方形、x形結(jié)構(gòu)元素:
//自定義核(結(jié)構(gòu)元素) cv::Mat_<uchar> cross(5,5); cv::Mat_<uchar> diamond(5,5); cv::Mat_<uchar> x(5,5); cv::Mat_<uchar> square(5,5); // Creating the cross-shaped structuring element cross << 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0; // Creating the diamond-shaped structuring element diamond << 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0; // Creating the x-shaped structuring element x << 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1; // Creating the square-shaped structuring element square << 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1; int xnr = x.rows; int xnl = x.cols; for(int j = 0;j<xnr;j++) { char *data = x.ptr<char>(j); for(int i = 0; i<xnl; i++) { int value = data[i]; std::cout<<value<<" "; } std::cout<<std::endl; }
三.形態(tài)學(xué)操作—腐蝕
腐蝕就是清除掉圖像的一些毛刺和細(xì)節(jié),腐蝕一般可以用來消除噪點(diǎn),分割出獨(dú)立的圖像元素等。其本質(zhì)上也是一種空間濾波,設(shè)定一個(gè)掩模,掩模中心逐次滑過每一個(gè)像素點(diǎn),當(dāng)前像素點(diǎn)(即掩模中心所對(duì)應(yīng)的位置)的值設(shè)為掩模覆蓋區(qū)域中像素的最小值。
腐蝕原理
膨脹或者腐蝕操作就是將圖像(或圖像的一部分區(qū)域,我們稱之為圖像A)與結(jié)構(gòu)元素(我們稱之為卷積核B)進(jìn)行卷積。核可以是任何的形狀和大小,擁有一個(gè)單獨(dú)定義出來的參考點(diǎn),我們稱其為錨點(diǎn)(anchorpoin)。多數(shù)情況下,核是一個(gè)小的中間帶有參考點(diǎn)和實(shí)心正方形或者圓盤,可以把核視為模板或者掩碼。掩膜中心位置的像素點(diǎn)是否與周圍領(lǐng)域的像素點(diǎn)顏色一樣(即是否是白色點(diǎn),即像素值是否為255),若一致,則保留,不一致則該點(diǎn)變?yōu)楹谏ㄖ导礊?)。
腐蝕函數(shù)API接口
dst=cv2.erode( InputArray src, OutputArray dst, InputArray kernel, Point anchor=Point(-1,-1), int iterations=1, int borderType=BORDER_CONSTANT, const Scalar& borderValue=morphologyDefaultBorderValue() );
參數(shù)說明:
第一個(gè)參數(shù),InputArray類型的src,輸入圖像,即源圖像,填Mat類的對(duì)象即可。圖像通道的數(shù)量可以是任意的,但圖像深度應(yīng)為CV_8U,CV_16U,CV_16S,CV_32F或 CV_64F其中之一。
第二個(gè)參數(shù),OutputArray類型的dst,即目標(biāo)圖像,需要和源圖片有一樣的尺寸和類型。
第三個(gè)參數(shù),InputArray類型的kernel,膨脹操作的核。若為NULL時(shí),表示的是使用參考點(diǎn)位于中心3x3的核。
我們一般使用函數(shù) getStructuringElement配合這個(gè)參數(shù)的使用。getStructuringElement函數(shù)會(huì)返回指定形狀和尺寸的結(jié)構(gòu)元素(內(nèi)核矩陣)。
其中,getStructuringElement函數(shù)的第一個(gè)參數(shù)表示內(nèi)核的形狀,我們可以選擇如下三種形狀之一:
- 矩形: MORPH_RECT
- 交叉形: MORPH_CROSS
- 橢圓形: MORPH_ELLIPSE
而getStructuringElement函數(shù)的第二和第三個(gè)參數(shù)分別是內(nèi)核的尺寸以及錨點(diǎn)的位置。
我們一般在調(diào)用erode以及dilate函數(shù)之前,先定義一個(gè)Mat類型的變量來獲得getStructuringElement函數(shù)的返回值。對(duì)于錨點(diǎn)的位置,有默認(rèn)值Point(-1,-1),表示錨點(diǎn)位于中心。且需要注意,十字形的element形狀唯一依賴于錨點(diǎn)的位置。而在其他情況下,錨點(diǎn)只是影響了形態(tài)學(xué)運(yùn)算結(jié)果的偏移。
getStructuringElement函數(shù)相關(guān)的調(diào)用示例代碼如下:
調(diào)用這樣之后,我們便可以在接下來調(diào)用erode或dilate函數(shù)時(shí),第三個(gè)參數(shù)填保存了getStructuringElement返回值的Mat類型變量。對(duì)應(yīng)于我們上面的示例,就是填element變量。
第四個(gè)參數(shù),Point類型的anchor,錨的位置,其有默認(rèn)值(-1,-1),表示錨位于中心。
第五個(gè)參數(shù),int類型的iterations,迭代使用erode()函數(shù)的次數(shù),默認(rèn)值為1。
第六個(gè)參數(shù),int類型的borderType,用于推斷圖像外部像素的某種邊界模式。注意它有默認(rèn)值BORDER_DEFAULT。
第七個(gè)參數(shù),const Scalar&類型的borderValue,當(dāng)邊界為常數(shù)時(shí)的邊界值,有默認(rèn)值morphologyDefaultBorderValue(),一般我們不用去管他。需要用到它時(shí),可以看官方文檔中的createMorphologyFilter()函數(shù)得到更詳細(xì)的解釋。
使用erode函數(shù),一般我們只需要填前面的三個(gè)參數(shù),后面的四個(gè)參數(shù)都有默認(rèn)值。而且往往結(jié)合getStructuringElement一起使用。
腐蝕的具體操作是:用一個(gè)結(jié)構(gòu)元素(一般是3×3的大小)掃描圖像中的每一個(gè)像素,用結(jié)構(gòu)元素中的每一個(gè)像素與其覆蓋的像素做“與”操作,如果都為1,則該像素為1,否則為0。
膨脹的具體操作是:用一個(gè)結(jié)構(gòu)元素(一般是3×3的大小)掃描圖像中的每一個(gè)像素,用結(jié)構(gòu)元素中的每一個(gè)像素與其覆蓋的像素做“與”操作,如果都為0,則該像素為0,否則為1。
代碼實(shí)現(xiàn):
#include"stdafx.h" #include <opencv2/opencv.hpp> #include <iostream> #include<stdio.h> using namespace cv; using namespace std; int _tmain(int argc, _TCHAR* argv[]) { Mat image1 = imread("F:/photo/qx.jpg", 1); namedWindow("input_picture1"); imshow("input_picture1", image1); Mat image2; Mat image3; cvtColor(image1, image2, COLOR_RGB2GRAY); namedWindow("input_picture2"); imshow("input_picture2", image2); threshold(image2, image3, 65, 255, THRESH_BINARY); namedWindow("input_picture3"); imshow("input_picture3", image3); Mat eroded; erode(image3, eroded, Mat()); namedWindow("erode"); imshow("erode", eroded); Mat dilated; dilate(image3, dilated, Mat()); namedWindow("dilate"); imshow("dilate", dilated); waitKey(0); return 0; }
圖像處理效果
原圖和灰度圖
灰度圖和二值化圖:
二值化圖像腐蝕膨脹效果:
到此這篇關(guān)于OpenCV圖像處理之實(shí)現(xiàn)圖像膨脹腐蝕操作的文章就介紹到這了,更多相關(guān)OpenCV圖像膨脹腐蝕內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入解析C++編程中基類與基類的繼承的相關(guān)知識(shí)
這篇文章主要介紹了C++編程中基類與基類的繼承的相關(guān)知識(shí),包括多個(gè)基類繼承與虛擬基類等重要知識(shí),需要的朋友可以參考下2016-01-01關(guān)于C語言函數(shù)strstr()的分析以及實(shí)現(xiàn)
以下是對(duì)C語言中strstr()函數(shù)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07C++如何計(jì)算二進(jìn)制數(shù)中1的個(gè)數(shù)
這篇文章主要介紹了C++如何計(jì)算二進(jìn)制數(shù)中1的個(gè)數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07Linux UDP服務(wù)端和客戶端程序的實(shí)現(xiàn)
這篇文章主要介紹了Linux UDP服務(wù)端和客戶端程序的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05基于OpenCv的運(yùn)動(dòng)物體檢測(cè)算法
這篇文章主要為大家詳細(xì)介紹了基于OpenCv的運(yùn)動(dòng)物體檢測(cè)算法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01Qt實(shí)現(xiàn)http服務(wù)的示例代碼
這篇文章將為大家詳細(xì)講解有關(guān)Qt如何實(shí)現(xiàn)http服務(wù),小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲2023-04-04C++ 基類指針和子類指針相互賦值的實(shí)現(xiàn)方法
下面小編就為大家?guī)硪黄狢++ 基類指針和子類指針相互賦值的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-12-12