从NMS谈起——自适应非极大值抑制算法(ANMS)

6 篇文章 0 订阅
4 篇文章 3 订阅

NMS,Bucketing,ANMS

上一章提到不管是NMS还是Bucketing的方法都无法获得最优的关键点空间分布。前者在窗口内避免了关键点的聚集效应,但是无法保证全局的均匀分布;后者能保证全局大概均匀分布,但是无法保证局部不聚集(当然目前的实现中往往opencv已经做了3x3的NMS,但是这种窗口的大小无法保证真正意义上的不聚集)。更大的问题是这这两种算法都有一些超参数需要手动调整,导致适用的场景有一定的限制。

为解决这一问题,Matthew Brown在论文Multi-Image Matching using Multi-Scale Oriented Patches提出了自适应非极大值抑制算法(Adaptive Non-Maximum Suppression,ANMS),实现了特征点在局部上的稀疏分布和全局上的均匀分布。

自适应非极大值抑制算法

自适应非极大值抑制算法基本思想是评估所有候选点的极大区域,并进行排序。

具体来说,就是先选取很多的评分较高的候选点,组成集合S。对S中的每个点 x i x_i xi,寻找它的响应能作为区域最大值的区域半径 r i r_i ri,即

r i = m i n ∣ ∣ x i − x j ∣ ∣ , s . t . r e s p o n s e ( x i ) < r e s p o n s e ( x j ) , x j ∈ S r_i =min||x_i-x_j||,s.t.response(x_i)<response(x_j),x_j \in S ri=minxixj,s.t.response(xi)<response(xj),xjS

将找到的 r i r_i ri降序排列。选取前n个元素对应的点,即为自适应非极大值滤波后得到的关键点。

算法效果如图:

过滤前

origin

过滤后

ANMS

有兴趣的话可以与上一章中的NMS和Bucketing的结果进行对比。

Why NOT ANMS

不同于传统非极大值抑制算法,ANMS算法不用选取阈值。然而带来的问题是它需要计算所有候选点之间的距离,所以会带来很大的时间复杂度,过滤10000个点得到1000个点,就需要耗费接近1s的时间。因此我们在在线的工作中很难看到ANMS得到应用。

实现代码如下


double computeR(Point2i x1, Point2i x2)
{
	return norm(x1 - x2);
}
template < typename T>
vector< size_t>  sort_indexes(const vector< T>  & v) {

	// initialize original index locations
	vector< size_t>  idx(v.size());
	for (size_t i = 0; i != idx.size(); ++i) idx[i] = i;

	// sort indexes based on comparing values in v
	sort(idx.begin(), idx.end(),
		[&v](size_t i1, size_t i2) {return v[i1] >  v[i2]; });

	return idx;
}

vector<KeyPoint> ANMS(const std::vector<KeyPoint>& kpts,int num = 500)
{
	int sz = kpts.size();
	double maxmum = 0;
	vector<double> roblocalmax(kpts.size());
	vector<double> raduis(kpts.size(), INFINITY);
	for (size_t i = 0; i < sz; i++)
	{
		auto rp = kpts[i].response;
		if (rp > maxmum)
			maxmum = rp;
		roblocalmax[i] = rp*0.9;
	}
	auto max_response = maxmum*0.9;
	for (size_t i = 0; i < sz; i++)
	{
		double rep = kpts[i].response;
		Point2i p = kpts[i].pt;
		auto& rd = raduis[i];
		if (rep>max_response)
		{
			rd = INFINITY;
		}
		else 
		{
			for (size_t j = 0; j < sz; j++)
			{
				if (roblocalmax[j] > rep)
				{
					auto d = computeR(kpts[j].pt, p);
					if (rd > d)
						rd = d;
				}
			}
		}
	}
	auto sorted = sort_indexes(raduis);
	vector<KeyPoint> rpts;
	
	for (size_t i = 0; i < num; i++)
	{
		rpts.push_back(kpts[sorted[i]]);
	}
	return std::move(rpts);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值