Opencv2.4学习::形态学滤波-角点检测

形态学滤波-角点检测


就是利用形态学处理中的腐蚀和膨胀操作进行的角点检测、边缘检测。


基本步骤

第一步:十字型核-------->【对原图:膨胀操作】

效果:原图在水平和垂直方向会扩展,而45度.135度方向没有得到扩展

目的:目的是使得在下一步的腐蚀操作中,保证腐蚀后的边缘与原图一致,而只有角点被腐蚀掉

第二步:菱形核-------->【对第一步的结果:腐蚀操作】

效果:使得第一步的结果在水平和垂直方向被腐蚀,而在45度.135度等方向也有一定腐蚀效果,使用菱形而不用十字进行腐蚀是为了斜方向得到腐蚀

第一步+第二部的最终结果:原图的边缘不发生变化,仅有角点被腐蚀

上图来源:https://blog.csdn.net/z827997640/article/details/80536547

个人认为,角点检测到这里就应该结束了,最后一步直接用原图与第二步的结果相减,就可以得出角点了

这里给出测试代码:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;
void main()
{
	Mat srcImg = imread("F:\\opencv_re_learn\\contour1.jpg");
	if (!srcImg.data){
		cout << "failed to read" << endl;
		system("pause");
		return;
	}
	Mat srcGray;
	cvtColor(srcImg, srcGray, CV_RGB2GRAY);
	Mat thresh;
	thresh = srcGray.clone();
	threshold(srcGray, thresh, 176, 255, CV_THRESH_BINARY_INV);
	imshow("thresh", thresh);
	//定义核
	Mat CrossMat(5, 5, CV_8U, Scalar(0));
	Mat diamondMat(5, 5, CV_8U, Scalar(1));
	Mat squareMat(5, 5, CV_8U, Scalar(1));
	Mat X(5, 5, CV_8U, Scalar(0));
	//十字形核
	for (int i = 0; i < 5; i++){
		CrossMat.at<uchar>(2, i) = 1;
		CrossMat.at<uchar>(i, 2) = 1;
	}
	//菱形形状核
	diamondMat.at<uchar>(0, 0) = 0;
	diamondMat.at<uchar>(0, 1) = 0;
	diamondMat.at<uchar>(1, 0) = 0;
	diamondMat.at<uchar>(4, 4) = 0;
	diamondMat.at<uchar>(3, 4) = 0;
	diamondMat.at<uchar>(4, 3) = 0;
	diamondMat.at<uchar>(4, 0) = 0;
	diamondMat.at<uchar>(4, 1) = 0;
	diamondMat.at<uchar>(3, 0) = 0;
	diamondMat.at<uchar>(0, 4) = 0;
	diamondMat.at<uchar>(0, 3) = 0;
	diamondMat.at<uchar>(1, 4) = 0;
	//X形状核
	for (int i = 0; i < 5; i++){
		X.at<uchar>(i, i) = 1;
		X.at<uchar>(4 - i, i) = 1;
	}
	//第一步:十字型核,【膨胀操作】
	//原图在水平和垂直方向会扩展,而45度.135度方向没有得到扩展
	//目的是使得在下一步的腐蚀操作中,保证腐蚀后的边缘与原图一致,
	//而只有角点被腐蚀掉
	Mat result;
	dilate(thresh, result, CrossMat);
	imshow("1:Cross", result);
	//第二步:菱形核,【腐蚀操作】
	//效果:使得第一步的结果在水平和垂直方向被腐蚀,而在45度.135度等方向也,
	//有一定腐蚀效果,使用菱形而不用十字进行腐蚀是为了斜方向得到腐蚀
	//第一第二步操作后的结果是:原图的边缘不发生变化,仅有角点被腐蚀
	erode(result, result, diamondMat);
	imshow("2:diamond", result);
	
	//计算差值
	absdiff(thresh, result, result);
	threshold(result, result, 30, 255, THRESH_BINARY);
	//绘制
	for (int i = 0; i < result.rows; i++){
		//获取行指针
		const uchar* data = result.ptr<uchar>(i);
		for (int j = 0; j < result.cols; j++){
			//如果是角点,则绘制圆圈
			if (data[j]){
				circle(srcImg, Point(j, i), 8,
					Scalar(0, 0, 255));
			}
		}
	}
	imshow("src", srcImg);
	imshow("result", result);
	waitKey(0);


}

测试结果: 


实际上,算法给出还有第三第四步

第三步: X型核-------->【对原图:膨胀操作】

效果:使得原图在水平和垂直,45度,135度等倾斜方向都有扩展

第四步:正方形核---------->【对第三步结果:腐蚀操作】

效果:又腐蚀掉一次

第三第四部操作后的结果是:原图角点不发生变化,而水平和垂直方向的边缘似乎被腐蚀掉

最后一步:将第二步与第四步的结果相减,获得角点


以上四步的全部代码如下:

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<iostream>
using namespace std;
using namespace cv;
void main()
{
	Mat srcImg = imread("F:\\opencv_re_learn\\contour1.jpg");
	if (!srcImg.data){
		cout << "failed to read" << endl;
		system("pause");
		return;
	}
	Mat srcGray;
	cvtColor(srcImg, srcGray, CV_RGB2GRAY);
	Mat thresh;
	thresh = srcGray.clone();
	threshold(srcGray, thresh, 176, 255, CV_THRESH_BINARY_INV);
	imshow("thresh", thresh);
	//定义核
	Mat CrossMat(5, 5, CV_8U, Scalar(0));
	Mat diamondMat(5, 5, CV_8U, Scalar(1));
	Mat squareMat(5, 5, CV_8U, Scalar(1));
	Mat X(5, 5, CV_8U, Scalar(0));
	//十字形核
	for (int i = 0; i < 5; i++){
		CrossMat.at<uchar>(2, i) = 1;
		CrossMat.at<uchar>(i, 2) = 1;
	}
	//菱形形状核
	diamondMat.at<uchar>(0, 0) = 0;
	diamondMat.at<uchar>(0, 1) = 0;
	diamondMat.at<uchar>(1, 0) = 0;
	diamondMat.at<uchar>(4, 4) = 0;
	diamondMat.at<uchar>(3, 4) = 0;
	diamondMat.at<uchar>(4, 3) = 0;
	diamondMat.at<uchar>(4, 0) = 0;
	diamondMat.at<uchar>(4, 1) = 0;
	diamondMat.at<uchar>(3, 0) = 0;
	diamondMat.at<uchar>(0, 4) = 0;
	diamondMat.at<uchar>(0, 3) = 0;
	diamondMat.at<uchar>(1, 4) = 0;
	//X形状核
	for (int i = 0; i < 5; i++){
		X.at<uchar>(i, i) = 1;
		X.at<uchar>(4 - i, i) = 1;
	}
	//第一步:十字型核,【膨胀操作】
	//原图在水平和垂直方向会扩展,而45度.135度方向没有得到扩展
	//目的是使得在下一步的腐蚀操作中,保证腐蚀后的边缘与原图一致,
	//而只有角点被腐蚀掉
	Mat result;
	dilate(thresh, result, CrossMat);
	imshow("1:Cross", result);
	//第二步:菱形核,【腐蚀操作】
	//效果:使得第一步的结果在水平和垂直方向被腐蚀,而在45度.135度等方向也,
	//有一定腐蚀效果,使用菱形而不用十字进行腐蚀是为了斜方向得到腐蚀
	//第一第二步操作后的结果是:原图的边缘不发生变化,仅有角点被腐蚀
	erode(result, result, diamondMat);
	imshow("2:diamond", result);
	//第三步:X型核对原图膨胀
	//效果:使得原图在水平和垂直,45度,135度等倾斜方向都有扩展
	Mat result2;
	dilate(thresh, result2, X);
	imshow("X", result2);
	//第四步:正方形核,【腐蚀操作】
	//效果:又腐蚀掉一次,第三第四部操作后的结果是,原图角点不发生变化,
	//而水平和垂直方向的边缘似乎被腐蚀掉
	erode(result2, result2, squareMat);
	imshow("squ", result2);
	//计算差值
	absdiff(result2, result, result);
	threshold(result, result, 30, 255, THRESH_BINARY);
	//绘制
	for (int i = 0; i < result.rows; i++){
		//获取行指针
		const uchar* data = result.ptr<uchar>(i);
		for (int j = 0; j < result.cols; j++){
			//如果是角点,则绘制圆圈
			if (data[j]){
				circle(srcImg, Point(j, i), 8,
					Scalar(0, 0, 255));
			}
		}
	}
	imshow("src", srcImg);
	imshow("result", result);
	waitKey(0);


}

猜你喜欢

转载自blog.csdn.net/dieju8330/article/details/83932483