基于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();
}

实验结果

猜你喜欢

转载自blog.csdn.net/victo_chao/article/details/84316692