首頁 > 軟體

OpenCV數位影像處理基於C++之影象形態學處理詳解

2022-12-07 14:00:55

1、影象腐蝕

原理:腐蝕用來收縮或細化二值影象中的前景,藉此實現去噪聲、元素分割等功能。和所有形態學濾波器一樣,腐蝕和膨脹這兩個濾波器的作用範圍是由結構元素定義的畫素集。在某個畫素上應用結構元素時,結構元素的錨點與該畫素對齊,所有與結構元素相交的畫素就包含在當前集合中。腐蝕就是把當前畫素替換成所定義畫素集合中的最小畫素值膨脹是腐蝕的反運算,它把當前畫素替換成所定義畫素集合中的最大畫素值。由於輸入的二值影象只包含黑色(值為0)和白色(值為255)畫素,因此每個畫素都會被替換成白色或黑色畫素。

​ 要形象地理解這兩種運算的作用,可考慮背景(黑色)和前景(白色)的物體。腐蝕時,如果結構元素放到某個畫素位置時碰到了背景(即交集中有一個畫素是黑色的),那麼這個畫素就變為背景;膨脹時,如果結構元素放到某個背景畫素位置時碰到了前景物體,那麼這個畫素就被標為白色。正因如此,影象腐蝕後物體尺寸會縮小(形狀被腐蝕),而影象膨脹後物體會擴大。在腐蝕影象中,有些面積較小的物體(可看作背景中的“噪聲”畫素)會徹底消失。與之類似,膨脹後的物體會變大.而物體中一些“空隙”會被填滿。OpenCV預設使用3×3正方形結構元素。在呼叫函數時,就能得到預設的結構元素。你也可以通過提供一個矩陣來指定結構元素的大小(以及形狀),矩陣中的非零元素將構成結構元素。

作用去除影象中的某些部分以及會縮小細化目標

1.1 CV腐蝕函數

CV_EXPORTS_W void erode( 
    InputArray src, 
    OutputArray dst, 
    InputArray kernel,
    Point anchor = Point(-1,-1),
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue()
);

src 輸入影象;通道的數量可以是任意的,但是深度值應該是以下之一:
CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
dst 和源影象同樣大小和型別的輸出影象。
kernel 用於腐蝕的結構元素;如果element=Mat(),是一個3 x 3的矩形結構元素. Kernel 可以通過使用getStructuringElement來建立。
anchor 素中的錨點的位置,預設是值(-1,-1),也就是說錨點在元素的中心位置。
iterations 腐蝕的迭代次數。
borderType畫素外推方法。參見#BorderTypes, BORDER_WRAP不支援。
borderValue 固定邊緣的情況下的邊緣值。
參考 dilate,morphologyEx,getStructuringElement
Mat cv::getStructuringElement(
int  shape,
Size  ksize,
Point  anchor = Point(-1,-1) 
 )
引數1:結構元的形狀(0:矩形結構元;1:十字架結構元;2:橢圓結構元);
引數2:結構元大小(size(m, n));
引數3:結構元中心點所在位置(point(x, y))預設為中心點
Mat element = getStructuringElement(0, Size(3, 3)); //構造矩形結構元素
	Mat image_erosion;
	erode(image_bw, image_erosion, element, Point(-1, -1), 3); //執行腐蝕操作
	imshow("image_erosion", image_erosion);

原圖

二值圖

CV腐蝕

1.2 自定義腐蝕函數

void erode_my(Mat &src,Mat &dst,int size) {
	for (int i = 0; i < src.rows; ++i)
	{
		for (int j = 0; j < src.cols; ++j)
		{
			uchar minV = 255;
			//uchar maxV = 0;

			//遍歷周圍最小畫素值
			for (int yi = i - size / 2; yi <= i + size / 2; yi++)
			{
				for (int xi = j - size / 2; xi <= j + size / 2; xi++)
				{
					if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows)
					{
						continue;
					}
					minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi));
					//maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi));			
				}
			}
			dst.at<uchar>(i, j) = minV;
		}
	}
}

自定義腐蝕

1.3 對比

erode_my(image_bw, image_erosion_my,9);
當腐蝕結構擴大到9×9時效果基本與cv自帶函數一致。

2、影象膨脹

原理:腐蝕用來收縮或細化二值影象中的前景,藉此實現去噪聲、元素分割等功能。腐蝕過程:用結構元來逐個畫素掃描被腐蝕影象,並根據結構元和被腐蝕影象的關係確定腐蝕結果。

注意,腐蝕操作等形態學操作,是逐個畫素地來確定值的,每次判定的點都與結構元中心點所對應,如果結構元完全處於前景影象中,就將結構元中心點所對應的腐蝕結果影象中的畫素點處理為前景色(如1)。如果結構元不完全處於前景影象中,就將結構元中心點所對應的腐蝕結果影象中的畫素點處理為背景色(如0)。(結構元也被稱為核

作用增大影象中的目標,或者填充、連線某些目標

2.1 CV膨脹函數

CV_EXPORTS_W void dilate( 
    InputArray src, 
    OutputArray dst, 
    InputArray kernel,
    Point anchor = Point(-1,-1), 
    int iterations = 1,
    int borderType = BORDER_CONSTANT,
    const Scalar& borderValue = morphologyDefaultBorderValue() 
);

src 輸入影象;通道的數量可以是任意的,但是深度值應該是以下之一:CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
dst 和源影象同樣大小和型別的輸出影象。
kernel 膨脹核元素,如果elemenat=Mat(), 是一個3 x 3的矩形核元素,核可以使用getStructuringElement來建立。
anchor 元素中的錨點的位置,預設是值(-1,-1),也就是說錨點在元素的中心位置。
iterations 膨脹的迭代次數。
borderType 畫素外推方法。參見#BorderTypes, BORDER_WRAP不支援。
borderValue 固定邊緣的情況下的邊緣值。
參考:erode,morphologyEx,getStructuringElement
//膨脹
Mat element = getStructuringElement(0, Size(3, 3)); //構造矩形結構元素
Mat image_dilate;
dilate(image_bw, image_dilate, element, Point(-1, -1), 9); //執行膨脹操作
imshow("image_dilate", image_dilate);

二值圖

CV膨脹

2.2 自定義膨脹函數

void dilate_my(Mat& src, Mat& dst, int size) {
	for (int i = 0; i < src.rows; ++i)
	{
		for (int j = 0; j < src.cols; ++j)
		{
			//uchar minV = 255;
			uchar maxV = 0;

			//遍歷周圍最大畫素值
			for (int yi = i - size / 2; yi <= i + size / 2; yi++)
			{
				for (int xi = j - size / 2; xi <= j + size / 2; xi++)
				{
					if (xi < 0 || xi >= src.cols || yi < 0 || yi >= src.rows)
					{
						continue;
					}
					//minV = (std::min<uchar>)(minV, src.at<uchar>(yi, xi));
					maxV = (std::max<uchar>)(maxV, src.at<uchar>(yi, xi));
				}
			}
			dst.at<uchar>(i, j) = maxV;
		}
	}
	
}

自定義膨脹

2.3 對比

dilate_my(image_bw, image_dilate_my, 9);
當膨脹結構擴大到9×9時效果基本與cv自帶函數一致。

腐蝕影象相當於對其反色影象膨脹後再取反色;
膨脹影象相當於對其反色影象腐蝕後再取反色。

3、開運算

原理先腐蝕,再膨脹

作用平滑物體輪廓、斷開狹窄的狹頸、消除細長的突出和物體。可以去掉影象上一些小的物件。(假設影象前景色是白色,背景色是黑色)

原圖

3.1 方法一

//先腐蝕後膨脹
Mat open_image;
Mat element = getStructuringElement(0, Size(3, 3)); //構造矩形結構元素
erode(image_bw, image_erosion, element, Point(-1, -1), 3); //執行腐蝕操作
dilate(image_erosion, open_image, element, Point(-1, -1), 3); //執行膨脹操作
imshow("open", open_image);

3.2 方法二

morphologyEx(image_bw, open_image, MORPH_OPEN, element);
	imshow("open2", open_image);

4、閉運算

原理先膨脹,再腐蝕

作用閉運算可以填充小洞,填充小的噪點

4.1 方法一

Mat close_image;
Mat element = getStructuringElement(0, Size(3, 3)); //構造矩形結構元素
dilate(image_bw, image_dilate, element, Point(-1, -1), 3); //執行膨脹操作
erode(image_dilate, close_image, element, Point(-1, -1), 3); //執行腐蝕操作
imshow("close", close_image);

4.2 方法二

morphologyEx(image_bw, close_image, MORPH_CLOSE, element);
imshow("close2", close_image);

4.3 morphologyEx函數介紹

void morphologyEx( 
InputArray src, 
OutputArray dst,
int op, 
InputArray kernel,
Point anchor = Point(-1,-1), 
int iterations = 1,
int borderType = BORDER_CONSTANT,
const Scalar& borderValue = morphologyDefaultBorderValue() 
);
(1)引數1:InputArray src
輸入影象,影象資料型別必須為CV_8U, CV_16U, CV_16S, CV_32F or CV_64F中的一種。
(2)引數2:OutputArray dst
輸出影象,資料型別與大小和輸入影象一樣。
(3)引數3:int op 形態學處理的型別:
MORPH_ERODE = 0:腐蝕處理
MORPH_DILATE = 1:膨脹處理
MORPH_OPEN = 2:開運算處理
MORPH_CLOSE = 3:閉運算處理
MORPH_GRADIENT = 4:形態學梯度
MORPH_TOPHAT = 5:頂帽變換
MORPH_BLACKHAT = 6:黑帽變換
MORPH_HITMISS = 7 :擊中-擊不中變換
(4)引數4:InputArray kernel結構元矩陣
(5)引數5:Point anchor = Point(-1,-1)
結構元中心點, 預設值Point(-1,-1), 表示正中心
(6)引數6:int iterations = 1
腐蝕膨脹處理的次數,預設值為1;
如果是開運算閉運算,次數表示先腐蝕或者膨脹幾次,再膨脹腐蝕幾次,而不是開運算閉運算幾次:
如開運算且次數為2:erode -> erode -> dilate -> dilate
(7)引數7:int borderType = BORDER_CONSTANT
影象邊框插值型別,預設型別為固定值填充
BORDER_CONSTANT = 0:固定值 i 填充:iiiiii | abcdefgh | iiiiiii
BORDER_REPLICATE = 1:兩端複製:aaaaaa | abcdefgh | hhhhhhh
BORDER_REFLECT = 2:映象複製:fedcba | abcdefgh | hgfedcb
BORDER_WRAP = 3:去除一端的值然後複製: cdefgh | abcdefgh | abcdefg
BORDER_REFLECT_101 = 4:去除一端的值然後映象複製: gfedcb|abcdefgh|gfedcba
BORDER_TRANSPARENT = 5:推導賦值 uvwxyz | abcdefgh | ijklmno
BORDER_REFLECT101 = BORDER_REFLECT_101: same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101: same as BORDER_REFLECT_101
BORDER_ISOLATED = 16:< do not look outside of ROI
(8)引數8:const Scalar& borderValue = morphologyDefaultBorderValue()
檔案中說明:param borderValue Border value in case of a constant border. The default value has a special meaning.

5、頂帽運算

原理頂帽(或禮帽)運算是原始影象減去影象開運算的結果。

頂帽運算:原始影象 — 影象開運算

作用:得到影象的噪聲。如下圖所示:

5.1 方法一

//構造結構元
Mat kernel = getStructuringElement(0, Size(5, 5));
Mat image_lm;
//頂帽變換(禮帽變換)
morphologyEx(image_bw, image_lm, 5, kernel);
cv::imshow("image_lm", image_lm);

5.2 方法二

Mat image_lm2;	//**頂帽運算:原始影象 — 影象開運算**
//dst=img1-img2;//這兩個減法效果相同    若dst<0,則dst=0
subtract(image_bw,open_image2, image_lm2);//注意:要求被處理圖片尺寸一致
cv::imshow("image_lm2",image_lm2);

Mat image_lm2;
absdiff(image_bw, open_image2, image_lm2);//若dst<0,則dst=|dst|>=0    用於檢測兩幅相似影象的不同點,效果比上面的兩種減法好
cv::imshow("image_lm2", image_lm2);

6、黑帽運算

原理黑帽運算是影象閉運算操作減去原始影象的結果。

黑帽運算:閉運算 — 原始影象

作用:得到影象內部的小孔,或者前景色中的小黑點。如下圖所示:

6.1 方法一

//構造結構元
Mat kernel = getStructuringElement(0, Size(5, 5));
//底帽變換(黑帽變換)
Mat image_hm;
morphologyEx(image_bw, image_hm, 6, kernel);
cv::imshow("image_hm", image_hm);

6.2 方法二

Mat image_hm2;
	subtract(image_bw, close_image2, image_hm2);//注意:要求被處理圖片尺寸一致
	cv::imshow("image_hm2", image_hm2);

Mat image_hm2;
absdiff(image_bw, close_image2, image_hm2);//若dst<0,則dst=|dst|>=0    用於檢測兩幅相似影象的不同點,效果比上面的兩種減法好
cv::imshow("image_hm2", image_hm2);

7、形態學梯度

原理膨脹圖與腐蝕圖之差;

作用對二值圖進行這一操作可以得到影象中白色區域的邊界,因此可以用形態學梯度來保留物體的邊界輪廓

7.1 方法一

//構造結構元
Mat kernel = getStructuringElement(0, Size(5, 5));
Mat image_lm;

//形態學梯度
morphologyEx(image_bw, image_td, 4, kernel);
cv::imshow("image_td", image_td);

7.2 方法二

Mat image_tw2;
subtract(image_dilate, image_erosion, image_tw2);//注意:要求被處理圖片尺寸一致
cv::imshow("image_tw2", image_tw2);

Mat image_tw2;
absdiff(image_dilate, image_erosion, image_tw2);//若dst<0,則dst=|dst|>=0    用於檢測兩幅相似影象的不同點,效果比上面的兩種減法好
cv::imshow("image_tw2", image_tw2);

部分參考來自:數位影像處理(c++ opencv)–持續更新 - 知乎 (zhihu.com)

總結

到此這篇關於OpenCV數位影像處理基於C++之影象形態學處理的文章就介紹到這了,更多相關OpenCV數位影像處理基於C++內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com