1. 程式人生 > >基於OpenCV的影象形態學處理

基於OpenCV的影象形態學處理

1、形態學概述
一詞通常表示生物學的個分支,該主要研究動植形態 和結構 。 而我們影象處理中的形態學,往指是數學形態學。
最基本的形態學操作有兩種:膨脹和腐蝕
膨脹:(dilate)就是求區域性最大值的操作。從數學角度來說,膨脹或者腐蝕操作就是講影象(或影象的一部分割槽域,稱之為A)與核(稱之為B)進行卷積。
膨脹和腐蝕:(erode)是相反的一對操作,所以腐蝕就是求區域性最小值的操作。
開運算:(Opening Operation),其實就是先腐蝕後膨脹的過程,開運算可以用來消除小物體,在纖細點處分離物體,並且在平滑較大物體的邊界的同時部明顯改變其面積。
閉運算:先膨脹後腐蝕的過程稱為閉運算(Closing Operation)。
2、實現影象的膨脹和腐蝕操作,開運算、閉運算
程式碼實現思路
1)載入原影象並顯示
2)建立兩個視窗並建立滾動條
3)輪詢獲取按鍵資訊
4)開運算和閉運算回撥函式
5)膨脹和腐蝕回撥函式
原始碼:

#include <iostream>  
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
Mat g_srcImage,g_dstImage;//原始圖和效果圖
int g_nElementShape =MORPH_RECT;
//變數接受的TrackBar位置引數
int g_nMaxIterationNum =10;
int g_nOpencloseNum =0;
int g_nErodeDilateNum =0;
//回撥函式..
static void on_OpenClose(int,void*);
static void on_ErodeDilate(int,void*);
static void on_TopBlackHat(int,void*);
int main()
{
	//載入原圖
	g_srcImage=imread("3.jpg");
	namedWindow("原始圖");
	imshow("原始圖",g_srcImage);
	//建立兩個創就並建立滾動條
	namedWindow("開運算/閉運算",1);
	namedWindow("腐蝕/膨脹",1);
	//引數賦值
	g_nOpencloseNum=9;
	g_nErodeDilateNum=9;
	createTrackbar("迭代值","開運算/閉運算",&g_nOpencloseNum,g_nMaxIterationNum*2+1,on_OpenClose);
	createTrackbar("迭代值","腐蝕/膨脹",&g_nErodeDilateNum,g_nMaxIterationNum*2+1,on_ErodeDilate);
	on_OpenClose(g_nOpencloseNum,0);
	on_ErodeDilate(g_nErodeDilateNum,0);
	while(1)
	{
		int c;
		c=waitKey(0);
		if((char)c=='q'||(c)==27)
			break;
	}
	return 0;
}
static void on_OpenClose(int,void*)
{
	//偏移量的定義
	int offset =g_nOpencloseNum-g_nMaxIterationNum;//偏移量
	int Absolute_offset =offset>0?offset:-offset;//偏移量絕對值
	//自定義核
	Mat element =getStructuringElement(g_nElementShape,Size(Absolute_offset*2+1,Absolute_offset*2+1),Point(Absolute_offset,Absolute_offset));
	//核的形狀  0:矩形  1:十字交叉形  2: 橢圓 Size ksize,//核大小 Point anchor=Point(-1,-1) //核中心位置,預設位於形狀中心處					 
	if(offset<0)
	{
		morphologyEx(g_srcImage,g_dstImage,CV_MOP_OPEN,element);
	}
	else
	{
		morphologyEx(g_srcImage,g_dstImage,CV_MOP_CLOSE,element);
	}
	imshow("開運算/閉運算",g_dstImage);
}

static void on_ErodeDilate(int,void*)
{
	//偏移量的定義
	int offset =g_nErodeDilateNum-g_nMaxIterationNum;//偏移量
	int Absolute_offset =offset>0?offset:-offset;//偏移量絕對值
	//自定義核
	Mat element =getStructuringElement(g_nElementShape,Size(Absolute_offset*2+1,Absolute_offset*2+1),Point(Absolute_offset,Absolute_offset));
	if(offset<0)
	{
		erode(g_srcImage,g_dstImage,element);
	}
	else
	{
		dilate(g_srcImage,g_dstImage,element);
	}
	imshow("腐蝕/膨脹",g_dstImage);
}

在這裡插入圖片描述
顯示的效果:
在這裡插入圖片描述
3、利用膨脹腐蝕提取灰度圖邊界

#include <iostream>  
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
Mat g_srcImage,g_dstImage,g_dstImage1,g_dstImage2;
Mat g_srcImageA,g_srcImageB,g_dstImage3,g_dstImage4,g_dstImage5;
int g_nElementShape =MORPH_RECT;// 矩形: MORPH_RECT 交叉形: MORPH_CROSS 橢圓形: MORPH_ELLIPSE 
int main()
{
	//載入原圖
	g_srcImage=imread("3.jpg");
	namedWindow("原始圖");
	imshow("原始圖",g_srcImage);
	Mat element =getStructuringElement(g_nElementShape,Size(3,3),Point(-1,-1));
	erode(g_srcImage,g_dstImage,element);
	dilate(g_srcImage,g_dstImage1,element);
	g_dstImage2=g_dstImage1-g_dstImage;
	imshow("實驗圖",g_dstImage2);
	waitKey();
}

效果圖:
在這裡插入圖片描述
4、根據擊中擊不中變換的原理,用程式碼實現影象的擊中尋找到B 圖(B.png)在A 圖(A.png)中的位置。
原始碼:

#include <iostream>  
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
Mat g_srcImage,g_dstImage,g_dstImage1,g_dstImage2;
Mat g_srcImageA,g_srcImageB,g_dstImage3,g_dstImage4,g_dstImage5;
int g_nElementShape =MORPH_RECT;// 矩形: MORPH_RECT 交叉形: MORPH_CROSS 橢圓形: MORPH_ELLIPSE 
int main()
{	
	g_srcImageA=imread("A.png");
	g_srcImageB=imread("B.png");
	cvtColor(g_srcImageA, g_srcImageA, CV_RGB2GRAY);
	cvtColor(g_srcImageB, g_srcImageB, CV_RGB2GRAY); //灰度值處理
	int threhold = 180;  
	threshold(g_srcImageA, g_srcImageA, threhold, 255, CV_THRESH_BINARY);  
	threshold(g_srcImageB, g_srcImageB, threhold, 255, CV_THRESH_BINARY); //二值化處理
	Mat ma = Mat::ones(g_srcImageA.size(), g_srcImageA.type());
	Mat g_srcImageA1=ma*255-g_srcImageA;
	Mat img_b;
	copyMakeBorder(g_srcImageB,img_b,1,1,1,1,IPL_BORDER_CONSTANT,Scalar(255));
	//imshow("加邊框",img_b);
	//imshow("A圖",g_srcImageA);
	Mat mb = Mat::ones(img_b.size(), img_b.type());
	Mat g_srcImageB1=mb*255-img_b;
	//imshow("B圖取反",g_srcImageB1);
	//imshow("A圖取反",g_srcImageA1);
	Mat hit_result, hit_result1, hit_result2; 
	erode(g_srcImageA, hit_result1,img_b, Point(-1,-1), 1 );
	imshow("第一次腐蝕", hit_result1); 
	erode(g_srcImageA1, hit_result2,g_srcImageB1, Point(-1,-1), 1);
	imshow("第二次腐蝕", hit_result2); 
	hit_result = hit_result1 & hit_result2;  
	imshow("擊中擊不中", hit_result);
	waitKey();
}

實驗結果