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;
}
得到的結果如下:

          












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