OpenCV用形态学方法进行图像线特征和角点的提取

1:图像形态学用于边缘的提取:

我们知道,图像膨胀后边缘会扩张,腐蚀后会紧缩,通过计算膨胀与紧缩的图像之差,就可以粗略的检测出图像的边缘;

int _tmain(int argc, _TCHAR* argv[])
{
	Mat image = imread("007.jpg",1);
	cvtColor(image,image,CV_RGB2GRAY);
	namedWindow("原图");
	imshow("原图",image);

	Mat eroded;
	erode(image,eroded,Mat());
	Mat dilated;
	dilate(image,dilated,Mat());

	Mat Edge = dilated-eroded;
	namedWindow("边缘");
	imshow("边缘",Edge);

	threshold(Edge,Edge,30,255,THRESH_BINARY);
	namedWindow("阈值边缘");
	imshow("阈值边缘",Edge);
	waitKey(0);
	return 0;
}
得到的结果:

     
除了做减法之外,morphologyEx() 函数直接提供了一个求边缘的参数,只需要修改第三个参数即可,得到的结果和上述一致;

int _tmain(int argc, _TCHAR* argv[])
{
	Mat image = imread("007.jpg",1);
	cvtColor(image,image,CV_RGB2GRAY);
	namedWindow("原图");
	imshow("原图",image);

	Mat Edge;
	morphologyEx(image,Edge,MORPH_GRADIENT,Mat());       //修改第三个参数,直接求边缘

	threshold(Edge,Edge,30,255,THRESH_BINARY);        
	namedWindow("阈值边缘");
	imshow("阈值边缘",Edge);
	waitKey(0);
	return 0;
}
2:图像形态学检测角点

角点最直观的印象就是水平和竖直方向上变换都很大,即X,Y的梯度都很大;边缘可以理解为X,Y方向上只有一个梯度大;而平坦地区水平竖直两个方向上的梯度都很小;角点不仅保留了图像的重要的特征,还有效地减少了信息的数据量,使其信息的含量很高,在三维场景重建、运动估计、目标跟踪与识别、图像的配准与匹配等计算机视觉领域有着非常重要的作用;

目前角点检测的方法主要有基于图像边缘的和基于图像灰度的,前者用的比较少,后者比较常见主要包括Harris算子,Moravec算子和Susan算子。

这里我们自定义一个类,用来实现图像角点的检测;

class MorphologyFeature
{
private:
	int Threshold;     //用于生成二值图像的阈值;
	//角点检测用到的结构元素;
	Mat cross;
	Mat diamond;
	Mat square;
	Mat x;

public:
	MorphologyFeature();
	Mat GetCorners(const Mat &image);
	void DrawOnImage(Mat &image,const Mat &binary);
	Mat getEdge(Mat &image)
	{
		Mat result;
		morphologyEx(image,result,MORPH_GRADIENT,Mat());
		applyThreshold(result);
		return result;
	}

	void applyThreshold(Mat &result)
	{
		if(threshold>0)
		{
			threshold(result,result,Threshold,255,THRESH_BINARY);
		}
	}
	void setThreshold(int a)
	{
		Threshold = a;
	}

};

MorphologyFeature::MorphologyFeature():Threshold(-1),cross(5,5,CV_8U,Scalar(0)),diamond(5,5,CV_8U,Scalar(1)),
	square(5,5,CV_8U,Scalar(1)),x(5,5,CV_8U,Scalar(0))
{
	//创建十字形元素
	for(int i=0;i<5;i++)
	{
		cross.at<uchar>(2,i) = 1;
		cross.at<uchar>(i,2) = 1;
	}
	//创建菱形元素
	diamond.at<uchar>(0,0)=0;
	diamond.at<uchar>(0,1)=0;
	diamond.at<uchar>(1,0)=0;
	diamond.at<uchar>(0,4)=0;
	diamond.at<uchar>(0,3)=0;
	diamond.at<uchar>(1,4)=0;
	diamond.at<uchar>(3,0)=0;
	diamond.at<uchar>(4,0)=0;
	diamond.at<uchar>(4,1)=0;
	diamond.at<uchar>(4,4)=0;
	diamond.at<uchar>(4,3)=0;
	diamond.at<uchar>(3,4)=0;

	//创建X型
	for(int i=0;i<5;i++)
	{
		x.at<uchar>(i,i) = 1;
		x.at<uchar>(i,4-i) = 1;
	}
}

Mat MorphologyFeature::GetCorners(const Mat &image)
{
	Mat result;
	//十字形膨胀;
	dilate(image,result,cross);
	//菱形腐蚀
	erode(result,result,diamond);

	Mat result2;
	//X型膨胀
	dilate(image,result2,x);
	//方形腐蚀
	erode(result2,result2,square);
	//通过两幅图像做差得到角点图像;
	absdiff(result2,result,result);
	applyThreshold(result);
	return result;
}

void MorphologyFeature::DrawOnImage(Mat &image,const Mat &binary)
{
	/*Mat_<uchar>::const_iterator it = binary.begin<uchar>();
	Mat_<uchar>::const_iterator itend = binary.end<uchar>();
	//遍历图像像素
	for(int i=0;it!=itend;it++,i++)
	{
		if(*it)
		{
			circle(image,Point(i*3%image.step,i*3/image.step),5,Scalar(0,255,0));
		}
	}*/
	for(int i=0;i<binary.rows;i++)
	{
		//获取行指针
		const uchar* data = binary.ptr<uchar>(i);
		for(int j=0;j<binary.cols;j++)
		{
			if(data[j])
			{
				circle(image,Point(j,i),5,Scalar(0,255,0));
			}
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	Mat image = imread("007.jpg",1);
	Mat image1 = image;
	cvtColor(image,image,CV_RGB2GRAY);
	namedWindow("原图");
	imshow("原图",image);

	MorphologyFeature morph;
	morph.setThreshold(10);

	Mat Edge = morph.GetCorners(image);
	morph.DrawOnImage(image1,Edge);

	namedWindow("角点");
	imshow("角点",Edge);
	namedWindow("结果");
	imshow("结果",image1);
	waitKey(0);
	return 0;
}
得到的结果如下:

          












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章