OpenCV_检测兴趣点

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30241709/article/details/78814054

在计算机视觉领域,兴趣点(也称关键点或特征点)的概念已经得到了广泛的应用,包括目标识别、图像配准、视觉跟踪、三维重建等。这个概念的原理是,从图像中选取某些特征点并对图像进行局部分析,而非观察整幅图像。

*检测图像中的角点

角点是很容易在图像中定位的局部特征,并且大量存在于人造物体中。角点的价值在于它是两条边缘线的接合点,是一种二维特征,可以被精确地定位(即使是子像素级精度)

Harris特征检测是检测角点地经典方法。

OpenCV中检测Harris角点地基本函数是cv::cornerHarris.调用该函数时输入一个图像,返回地结果是一个浮点型图像,其中每个像素点表示角点强度

原图:


效果:


代码:

HarrisDetector类:

class HarrisDetecter
{
private:
	cv::Mat cornerStrength;		//32位浮点数型的角点强度图像
	cv::Mat cornerTh;		//32位浮点数型的阈值化角点图像
	cv::Mat localMax;		//局部最大值图像
	int neighbourhood;		//平滑导数的邻域尺寸
	int aperture;			//梯度计算的口径
	double k;				//Harris参数
	double maxStrength;		//阈值计算的最大强度
	double threshold;		//计算得到的阈值
	int nonMaxSize;			//非最大抑制的邻域尺寸
	cv::Mat kernel;			//非最大抑制内核
public:
	HarrisDetecter() :neighbourhood(3), aperture(3), k(0.01), maxStrength(0.0), threshold(0.01), nonMaxSize(3)
	{
		setLocalMaxWindowSize(nonMaxSize);
	}
	void setLocalMaxWindowSize(int size)
	{
		nonMaxSize = size;
		kernel.create(nonMaxSize, nonMaxSize, CV_8U);
	}
	void detect(const cv::Mat& image)
	{
		cv::cornerHarris(image, cornerStrength, neighbourhood, aperture, k);
		//计算内部阈值
		double minStrength;
		cv::minMaxLoc(cornerStrength, &minStrength, &maxStrength);
		//检测局部最大值
		cv::Mat dilated;
		cv::dilate(cornerStrength, dilated, cv::Mat());
		cv::compare(cornerStrength, dilated, localMax, cv::CMP_EQ);
	}
	//用Harris值得到角点分布图
	cv::Mat getCornerMap(double qualityLevel)
	{
		cv::Mat cornerMap;
		threshold = qualityLevel*maxStrength;
		cv::threshold(cornerStrength, cornerTh, threshold, 255, cv::THRESH_BINARY);
		cornerTh.convertTo(cornerMap, CV_8U);
		//非最大值抑制
		cv::bitwise_and(cornerMap, localMax, cornerMap);
		return cornerMap;
	}
	//用Harris值得到角点分布图
	void getCorners(std::vector<cv::Point>& points, double qualityLevel)
	{
		cv::Mat cornerMap = getCornerMap(qualityLevel);
		getCorners(points, cornerMap);
	}
	void getCorners(std::vector<cv::Point>& points, const cv::Mat& cornerMap)
	{
		for (int y = 0; y < cornerMap.rows; y++)
		{
			const uchar* rowPtr = cornerMap.ptr<uchar>(y);
			for (int x = 0; x < cornerMap.cols; x++)
			{
				if (rowPtr[x])
				{
					points.push_back(cv::Point(x, y));
				}
			}
		}

	}
	void drawOnImage(cv::Mat& image, const std::vector<cv::Point>& points,
		cv::Scalar color = cv::Scalar(255, 255, 255), int radius = 3, int thickness = 1)
	{
		std::vector<cv::Point>::const_iterator it = points.begin();
		while (it != points.end())
		{
			cv::circle(image, *it, radius, color, thickness);
			it++;
		}
	}
};

main函数:

int main()
{
	cv::Mat image = cv::imread("church.jpg");
	cv::cvtColor(image, image, CV_BGR2GRAY);
	cv::imshow("original image", image);
	HarrisDetecter harris;
	harris.detect(image);
	std::vector<cv::Point>pts;
	harris.getCorners(pts, 0.02);
	harris.drawOnImage(image, pts);
	cv::imshow("harris detected", image);
	cvWaitKey();

}
错误记录:

在使用cv::cornerHarris()函数时报错,查阅官方文档:



其src为8位图像或浮点点图,故加载彩色图时image为CV_8U3

执行

cv::cvtColor(image, image, CV_BGR2GRAY);

语句后再次执行cv::cornerHarris()函数正确。

实现原理:


(因教材中公式有少量错误,故重新整理)

*适合跟踪的特征

有两个函数可以用来显式地计算Harris协方差矩阵地特征值(以及特征向量),即cv::cornerEignValAndVecs和cv::cornerMinEigenVal

还有一种对Harris地改进是针对特征点聚集地问题(兴趣点在图像中分布不均匀,聚集在高度纹理化地位置),改进的算法从Harris值最强的点开始,只允许一定距离之外的点成为兴趣点。,在OpenCV中调用函数

cv::goodFeaturesToTrack

实现这个算法,之所以采用这个函数名称,因为它检测到的特征非常适合作为视觉跟踪程序的起始集合。

cv::goodFeaturesToTrack与cv::coenerHarris效果的对比:

代码:

std::vector<cv::Point> corners;
	cv::goodFeaturesToTrack(image, corners,
		500,//返回角点的最大数量
		0.01,//质量等级
		10);//角点间允许的最大距离

*快速检测特征

Harris算子对角点做出了规范的数学定义,该定义基于在两个相互垂直的方向上强度值的变化率。虽然这是一种很完美的定义,但是它需要计算图像的导数,而计算导数非常耗时

FAST(加速分割测试获得特征,Features from Accelerated Segment Test)专门用来快速检测兴趣点,只要对比几个像素,就可以判断是否为关键点。

在OpenCV中,检测特征点有通用接口,因此调用任何特征点检测器都非常容易。

结果:


代码:

int main()
{
	cv::Mat image = cv::imread("church.jpg");
	std::vector<cv::KeyPoint> keypoints;
	cv::Ptr<cv::FastFeatureDetector> fast = cv::FastFeatureDetector::create(40);
	fast->detect(image, keypoints);
	cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255), cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);
	cv::imshow("detected", image);
	cvWaitKey();
}


错误记录:

在OpenCV3.3中,FastFeatureDetector为抽象类,不能实例化

FAST检测器的使用方法为:

std::vector<cv::KeyPoint> keypoints;
cv::Ptr<cv::FastFeatureDetector> fast = cv::FastFeatureDetector::create(40);
fast->detect(image, keypoints);
OpenCV提供了在图像上画关键点的通用函数:

cv::drawKeypoints()

实现原理:

①测试圆周上相隔90°的四个点,若至少三个点都比圆心更亮或者更暗,进入②;

②检测圆上的像素点,如果存在这样一个圆弧,它的连续长度超过周长的3/4,并且它上面所有的像素强度值都与圆心的强度值明显不同,就确认为一个关键点。

*适配的特征检测

如果要更好地控制被检测特征点地数量,可使用cv::FeatureDetector的一个专门的子类,即cv::DynamicAdaptedFeatureDetector.它可以指定被检测兴趣点的数量范围。

这时使用FAST特征检测器的方法如下:

cv::DynamicAdaptedFeatureDetector fastD(

new cv::FastAdjuster(40),//特征检测器

150,//特征的最小数量

200,//特征的最大数量

50);//最大迭代次数

fastD.detect(image,keypoints);//检测特征点
(在OpneCV3.3.1官方文档中没有找到这个类)

*网格适配特征检测

实际上在检测图像中的关键点时,经常出现这种情况,即很多兴趣点聚集在特定的纹理区域,cv::GridAdaptedFeatureDetector可以在图像上定义一个网格,网格中的每个单元格可以设置一个最大元素数量。这里的理念是把被检测的关键点以更好的方式扩展到整幅图像上。

(OpenCV3.3.1的官方文档中同样没有找到这个类)

*尺度不变特征检测

计算机视觉界尺度不变特征的理念是:不仅在任何尺度下拍摄的物体都能检测到一致的关键点,而且每个被检测的特征点都对应一个尺度因子。

理想情况下,对于两幅图像中不同尺度的同一个物体点,计算得到的两个尺度因子之间的比率应该等于图像尺度的比率。

SURF全称“加速稳健特征”(Speeded Up Robust Feature),它们不仅是尺度不变特征,而且是具有较高计算效率的特征。

实现:

cv::Ptr<cv::FeatureDetector>detector = new cv::SURF(2000.0);//阈值
detector->detect(image,keypoints);
cv::drawKeypoints(image,keypoints,image,cv::Scalar(255,255,255),cv::DrawMatchedFlags::DRAW_RICH_KEYPOINTS);
使用DRAW_RICH_KEYPOINTS可得到关键点的圆,并且 圆的尺寸与每个特征计算得到的尺度成正比。为了使特征具有旋转不变性,SURF还让每个特征关联了一个方向,方向由院内的一条辐射线表示。

实现原理:

①对每个像素计算Hessian矩阵


②根据矩阵的行列式的值,得到曲率的强度。该方法把角点定义为局部高曲率(即在多个方向上的变化幅度都很高)

Hessian矩阵的行列式值达到了局部最大值,那么就认为这是一个尺度不变性特征。

*SIFT特征检测算法

SUFR算法是SIFT算法的加速版,SIFT(尺度不变特征转换,Scale-Invariant Feature Transform)也采用图像空间和尺度空间的局部最大值,但它使用拉普拉斯滤波器响应而不是Hessian行列式值。SIFT算法检测的特征在空间和尺度上的定位更加精确,但是计算效率低

调用方法:

cv::Ptr<cv::FeatureDetector>detector = new cv::SIFT();//阈值
detector->detect(image,keypoints);
cv::drawKeypoints(image,keypoints,image,cv::Scalar(255,255,255),cv::DrawMatchedFlags::DRAW_RICH_KEYPOINTS);
*多尺度FAST特征的检测

1、BRISK(Binary Robust Invariant Scalable Keypoints,二元稳健恒定可扩展关键点)检测法,基于FAST特征检测法


代码:

int main()
{
	cv::Mat image = cv::imread("church.jpg");
	std::vector<cv::KeyPoint> keypoints;
	cv::Ptr<cv::Feature2D> detector = cv::BRISK::create();
	detector->detect(image, keypoints);
	cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	cv::imshow("BRISK", image);
	cvWaitKey();

}
*ORB特征检测算法

ORB代表定向FAST和旋转BRIEF(Oriented FAST and Rotated BRIEF)

这个缩写的第一层一丝表示关键点检测,第二层意思表示ORB算法提供的描述子。

效果:


代码:

int main()
{
	cv::Mat image = cv::imread("church.jpg");
	std::vector<cv::KeyPoint> keypoints;
	cv::Ptr<cv::Feature2D> detector = cv::ORB::create(200,1.2,8);
	detector->detect(image, keypoints);
	cv::drawKeypoints(image, keypoints, image, cv::Scalar(255, 255, 255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
	cv::imshow("BRISK", image);
	cvWaitKey();
}


猜你喜欢

转载自blog.csdn.net/qq_30241709/article/details/78814054