1. 程式人生 > >opencv形態學理解

opencv形態學理解

形態學知識

/**************************************************************************/

-代表腐蝕
+代表膨脹
*代表匹配
一下針對的是二值影象,圖片指黑底白字
腐蝕
A-B={z|(B)z包含於A}
1.該式指出B對A的腐蝕是一個用z平移的B包含在A中的所有的點z的集合
2.等價於B不與北京共享任何公共元素。
膨脹
A+B={z|(B補)z交A!=空集}
1.該公式是以B關於它的原點的映像,並且以z對映像進行平移為基礎的。B對A的膨脹是所有位移z的集合,B補和A至少有一個元素是重疊的。
腐蝕會細化影象,膨脹會粗化影象
開操作

    A。B=(A-B)+B    
1.先腐蝕後膨脹,結果是一般會平滑物體的輪廓,斷開較窄的狹頸並消除細的突出物
理解:先腐蝕會消除掉比SE小的區域,然後再度膨脹,小的物體會變大,沒了的物體就依舊是沒了
閉操作    A. B=(A+B)-B
1.先膨脹後腐蝕,通常會彌合較窄的間斷和細長的溝壑,消除小的孔洞,填充輪廓線中的斷裂
理解:由於膨脹會把原來細小的點,間斷點連線起來,再腐蝕會把周圍變細,但是內部不變。
擊中與擊不中變換    A*B=(A-D)交(A補-(W減去D))
理解:不是特別懂。大概就是把B在A中給匹配出來,並且標記為1;在不需要匹配背景的情況下,便可以簡化為腐蝕
一些基本的形態學演算法

1.邊界提取    邊界=A減去(A-B)
理解:B腐蝕掉A就會得到A小一圈的部分(即內部),實心圖減去內部即得到一個環(邊界)
2.孔洞填充    Xk=(Xk-1+B)交A補    迭代至Xk和Xk-1相等為止,然後Xk和原圖取交集即可
條件:每個孔洞要預先有填充一個點,B={0,1,0,1,1,1,0,1,0},針對八連通的孔洞
理解:每次對Xk-1進行膨脹時,都會在之前的點的上下左右填充哦你一個點,然後再通過與A補求交集即可得到一個填充區域,最後填充區域與原圖求並集就能夠填充原圖的孔洞。
3.連通分量的提取 
   Xk=(Xk-1+B)交A    迭代至Xk和Xk-1相等為止
條件:在連通區域要有先填充一個點,B(3,3,CV_8U,Scalar::all(1)),針對八連通的區域
理解:每次對Xk-1進行膨脹時,都會在之前的點周圍的八個點填充,然後通過與原圖求交集即去掉多餘的點,即可得到八連通的區域
4.凸殼    Xk=(Xk-1*B)並A    迭代至Xk和Xk-1相等為止,執行B1,2,3,4,最終將4個並集起來,即可得到凸殼
B={1,X,X
   1,0,X
   1,X,X} B1,2,3,4依次旋轉90度
理解:對Xk-1無限次匹配B則會在最右側形成階梯的形狀,向中間靠攏,直到最右側只有1或2個高度。其他方向一樣理解,並集則是確保包含A,最終4個Xk求並集便是凸殼
5.細化       A細化B=A-(A*B)
當{B}={B1,1,2,3,4,5}時。A細化{B}=(((A細化B1)細化B2)細化B3)……
6.粗化      A粗化B=A並(A*B)
形態學重建
測地膨脹    對集合進行膨脹後與模板求交集,迭代至不再變化為止
測地腐蝕    對集合進行腐蝕後與模板求補集,迭代至不再變化為止
重建開操作提取長字母的理解
先對原圖進行n次腐蝕,後進行測地膨脹。n次腐蝕可以提取出原圖中長字母的一個點,由於每個字母中間有間隔,每次進行測地膨脹的時候,無關的值在求交集的過程中去掉了,剩下了連續的,與原來模板相關的值。
對填充孔洞,實現字母塗黑的理解
對邊界取反色,然後其餘部分為黑色,從邊界開始以原圖的補為模板進行測地膨脹,得到的結果便是原來的白色字型變成了黑色,被黑色字型包圍起來的圈也是黑色,其餘部分是白色,再對這張圖取反,就得到了白色字型裡面的白色孔洞被填充了。
邊界清除的理解
保留邊界的點,然後從這些點開始以原圖為模板進行測地膨脹,把原圖減去這個結果即可。

灰度級形態學

腐蝕操作,取覆蓋區域的最小值
膨脹操作,取覆蓋區域的最大值
開操作,在一維的理解下可以認為是一條橫線從下往上滑動的最大高度,會截去比較細的部分,變平。
閉操作,從上往下滑動的最低程度,截去低谷部分,變平。
形態學平滑,先進行開操作,再進行閉操作。
形態學梯度,g=(f+b)-(f-b),可以得到和二維微分影象類似的效果。
頂帽變換That=f-(f開b),得到暗背景上的亮物體,可以用來矯正不均勻光照的影響
底帽變換Bhat=f閉b-f,達到的亮背景上的暗物體
灰度級形態學重建
測地膨脹f=min((f+b),g),一樣是迭代至不變化為止
測地腐蝕f=max((f-b),g),同上

/**************************************************************************************************************/

介紹一下opencv函式

dilate=膨脹

 

erode=腐蝕

以上來自於opencv的使用手冊

/****************************************************************************************************/

以下是例程(提取長字母和填充字母中的孔洞)

 

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int check_mat(Mat&a,Mat&b)/*判斷兩幅影象是否相同*/
{
	int ra=a.rows;
	int ca=a.cols;
	int rb=b.rows;
	int cb=b.cols;
	if(ra!=rb || ca!=cb)return 0;
	for(int i=0;i<ra;i++)
	{
		char *pa=a.ptr<char>(i);
		char *pb=b.ptr<char>(i);
		for(int j=0;j<ca;j++)
		if(pa[j]!=pb[j])return 0;
	}
	return 1;
}
void border_f(Mat &src)/*取邊框反色,其餘置0*/
{
	int r=src.rows;
	int c=src.cols;
	for(int i=0;i<r;i++)
	{
		char*p=src.ptr<char>(i);
		p[0]=255-p[0];
		p[c-1]=255-p[c-1];
	}
	char*p=src.ptr<char>(0);
	for(int i=1;i<c-1;i++)
		p[i]=255-p[i];
	p=src.ptr<char>(r-1);
	for(int i=1;i<c-1;i++)
		p[i]=255-p[i];
	for(int i=1;i<r-1;i++)
	{
		char*pt=src.ptr<char>(i);
		for(int j=1;j<c-1;j++)
		pt[j]=0;
	}
		
}
int main(int a,char **p)
{
	Mat src=imread("eng.png",CV_LOAD_IMAGE_GRAYSCALE);//載入灰度影象
	threshold(src,src,180,255,1);//二值化,由於我的影象是黑字白底的,所以最後一個引數取1,變成白字黑底
	imshow("src",src);
	Mat kern(10,1,CV_8U,Scalar::all(1));//長字元的SE
	Mat kern2(3,3,CV_8U,Scalar::all(1));//3*3的SE
	Mat old_output;
	erode(src,old_output,kern);//腐蝕
	dilate(old_output,old_output,kern);//膨脹
	/*腐蝕再膨脹,便是開操作*/
	imshow("old_ouput",old_output);
	
	Mat re_output;
	erode(src,re_output,kern);
	Mat last_output;
	imshow("re",re_output);
	//*****************重建開操作******************
	do{
	last_output=re_output.clone();
	dilate(re_output,re_output,kern2);
	re_output=re_output&src;
	}while(!check_mat(last_output,re_output));
	imshow("re_output",re_output);/*提取出了長字元*/
	//******************填充孔洞*******************
	Mat F=src.clone();/*拷貝一份*/
	border_f(F);
	imshow("border_f",F);
	Mat Ic=Mat::ones(src.size(),CV_8UC1)*255-src;
	re_output=F;
	do
	{
	last_output=re_output.clone();
	dilate(re_output,re_output,kern2);
	re_output=re_output&Ic;
	}while(!check_mat(last_output,re_output));
	Mat H=Scalar::all(255)-re_output;
	imshow("oo",H);/*填充了孔洞*/
	waitKey();
	
	return 0;
}

 

abc

def

a是輸入的原圖

b是腐蝕後的效果

c是一般的開操作的結果

d是重建開操作後的結果

e是邊界取反色,其餘置0的效果

f是孔洞填充的效果