Swarm-SLAM  1.0.0
C-SLAM Framework
scancontext_matching.py
Go to the documentation of this file.
1 import cslam.lidar_pr.scancontext_utils as sc_utils
2 import numpy as np
3 from scipy import spatial
4 
5 class ScanContextMatching(object):
6  """Nearest Neighbor matching of description vectors
7  """
8 
9  def __init__(self, shape=[20,60], num_candidates=10, threshold=0.15):
10  """ Initialization
11  Default configs are the same as in the original paper
12 
13  """
14  self.shapeshape = shape
15  self.num_candidatesnum_candidates = num_candidates
16  self.thresholdthreshold = threshold
17 
18  self.scancontextsscancontexts = np.zeros((1000, self.shapeshape[0], self.shapeshape[1]))
19  self.ringkeysringkeys = np.zeros((1000, self.shapeshape[0]))
20  self.itemsitems = dict()
21  self.nb_itemsnb_items = 0
22 
23  def add_item(self, descriptor, item):
24  """Add item to the matching list
25 
26  Args:
27  descriptor (np.array): descriptor
28  item: identification info (e.g., int)
29  """
30  sc = descriptor.reshape(self.shapeshape)
31 
32  if self.nb_itemsnb_items >= len(self.ringkeysringkeys):
33  self.scancontextsscancontexts.resize((2 * len(self.scancontextsscancontexts), self.shapeshape[0], self.shapeshape[1]),
34  refcheck=False)
35  self.ringkeysringkeys.resize((2 * len(self.ringkeysringkeys), self.shapeshape[0]),
36  refcheck=False)
37 
38  rk = sc_utils.sc2rk(sc)
39 
40  self.scancontextsscancontexts[self.nb_itemsnb_items] = sc
41  self.ringkeysringkeys[self.nb_itemsnb_items] = rk
42  self.itemsitems[self.nb_itemsnb_items] = item
43 
44  self.nb_itemsnb_items = self.nb_itemsnb_items + 1
45 
46  def search(self, query, k):
47  """Search for nearest neighbors
48 
49  Args:
50  query (np.array): descriptor to match
51  k (int): number of best matches to return
52 
53  Returns:
54  list(int, np.array): best matches
55  """
56  if self.nb_itemsnb_items < 1:
57  return [None], [None]
58 
59  # step 1
60  ringkey_history = np.array(self.ringkeysringkeys[:self.nb_itemsnb_items])
61  ringkey_tree = spatial.KDTree(ringkey_history)
62 
63  query_sc = query.reshape(self.shapeshape)
64  ringkey_query = sc_utils.sc2rk(query_sc)
65  _, nncandidates_idx = ringkey_tree.query(ringkey_query, k=self.num_candidatesnum_candidates)
66 
67  # step 2
68  nn_dist = 1.0 # initialize with the largest value of distance
69  nn_idx = None
70  nn_yawdiff = None
71  for ith in range(self.num_candidatesnum_candidates):
72  candidate_idx = nncandidates_idx[ith]
73  candidate_sc = self.scancontextsscancontexts[candidate_idx]
74  dist, yaw_diff = sc_utils.distance_sc(candidate_sc, query_sc)
75  if(dist < nn_dist):
76  nn_dist = dist
77  nn_yawdiff = yaw_diff
78  nn_idx = candidate_idx
79 
80  if nn_idx is None:
81  nn_idx = 0
82  nn_yawdiff_deg = 0
83  similarity = 0.0
84  else:
85  nn_yawdiff_deg = nn_yawdiff * (360/self.shapeshape[1])
86  similarity = 1 - nn_dist # For now we return only 1 match, but we could return the n best matches
87  return [self.itemsitems[nn_idx]], [similarity]
88 
89  def search_best(self, query):
90  """Search for the nearest neighbor
91  Implementation for compatibily only
92 
93  Args:
94  query (np.array): descriptor to match
95 
96  Returns:
97  int, np.array: best match
98  """
99  if self.nb_itemsnb_items < 1:
100  return None, None
101 
102  idxs, sims = self.searchsearch(query, 1)
103 
104  return idxs[0], sims[0]
def __init__(self, shape=[20, 60], num_candidates=10, threshold=0.15)