这是我为基于 KD-Tree 的局部非最大特征抑制编写的一个简单的 Python 实现。它假设 kps 是一组 opencv 2d 稀疏特征(SIFT、SURF、AKAZE 等)。
它根据(降序)分数对特征进行排序,然后按分数顺序开始查询它们,从集合中删除高分特征的邻居(并避免它们未来的查询以提高效率)
将 r 调整为您想要的空间稀疏度,并根据特征的初始密度调整 k_max。
from scipy.spatial.kdtree import KDTree
import numpy as np
def KDT_NMS(kps, descs=None, r=15, k_max=20):
""" Use kd-tree to perform local non-maximum suppression of key-points
kps - key points obtained by one of openCVs 2d features detectors (SIFT, SURF, AKAZE etc..)
r - the radius of points to query for removal
k_max - maximum points retreived in single query
"""
# sort by score to keep highest score features in each locality
neg_responses = [-kp.response for kp in kps]
order = np.argsort(neg_responses)
kps = np.array(kps)[order].tolist()
# create kd-tree for quick NN queries
data = np.array([list(kp.pt) for kp in kps])
kd_tree = KDTree(data)
# perform NMS using kd-tree, by querying points by score order,
# and removing neighbors from future queries
N = len(kps)
removed = set()
for i in range(N):
if i in removed:
continue
dist, inds = kd_tree.query(data[i,:],k=k_max,distance_upper_bound=r)
for j in inds:
if j>i:
removed.add(j)
kp_filtered = [kp for i,kp in enumerate(kps) if i not in removed]
descs_filtered = None
if descs is not None:
descs = descs[order]
descs_filtered = np.array([desc for i,desc in enumerate(descs) if i not in removed],dtype=np.float32)
print('Filtered',len(kp_filtered),'of',N)
return kp_filtered, descs_filtered