FeatureDatabase.cpp
Go to the documentation of this file.
1 /*
2  * OpenVINS: An Open Platform for Visual-Inertial Research
3  * Copyright (C) 2018-2023 Patrick Geneva
4  * Copyright (C) 2018-2023 Guoquan Huang
5  * Copyright (C) 2018-2023 OpenVINS Contributors
6  * Copyright (C) 2018-2019 Kevin Eckenhoff
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "FeatureDatabase.h"
23 
24 #include "Feature.h"
25 #include "utils/print.h"
26 
27 using namespace ov_core;
28 
29 std::shared_ptr<Feature> FeatureDatabase::get_feature(size_t id, bool remove) {
30  std::lock_guard<std::mutex> lck(mtx);
31  if (features_idlookup.find(id) != features_idlookup.end()) {
32  std::shared_ptr<Feature> temp = features_idlookup.at(id);
33  if (remove)
34  features_idlookup.erase(id);
35  return temp;
36  } else {
37  return nullptr;
38  }
39 }
40 
42  std::lock_guard<std::mutex> lck(mtx);
43  if (features_idlookup.find(id) == features_idlookup.end())
44  return false;
45  // TODO: should probably have a copy constructor function in feature class
46  std::shared_ptr<Feature> temp = features_idlookup.at(id);
47  feat.featid = temp->featid;
48  feat.to_delete = temp->to_delete;
49  feat.uvs = temp->uvs;
50  feat.uvs_norm = temp->uvs_norm;
51  feat.timestamps = temp->timestamps;
52  feat.anchor_cam_id = temp->anchor_cam_id;
53  feat.anchor_clone_timestamp = temp->anchor_clone_timestamp;
54  feat.p_FinA = temp->p_FinA;
55  feat.p_FinG = temp->p_FinG;
56  return true;
57 }
58 
59 void FeatureDatabase::update_feature(size_t id, double timestamp, size_t cam_id, float u, float v, float u_n, float v_n) {
60 
61  // Find this feature using the ID lookup
62  std::lock_guard<std::mutex> lck(mtx);
63  if (features_idlookup.find(id) != features_idlookup.end()) {
64  // Get our feature
65  std::shared_ptr<Feature> feat = features_idlookup.at(id);
66  // Append this new information to it!
67  feat->uvs[cam_id].push_back(Eigen::Vector2f(u, v));
68  feat->uvs_norm[cam_id].push_back(Eigen::Vector2f(u_n, v_n));
69  feat->timestamps[cam_id].push_back(timestamp);
70  return;
71  }
72 
73  // Debug info
74  // PRINT_DEBUG("featdb - adding new feature %d",(int)id);
75 
76  // Else we have not found the feature, so lets make it be a new one!
77  std::shared_ptr<Feature> feat = std::make_shared<Feature>();
78  feat->featid = id;
79  feat->uvs[cam_id].push_back(Eigen::Vector2f(u, v));
80  feat->uvs_norm[cam_id].push_back(Eigen::Vector2f(u_n, v_n));
81  feat->timestamps[cam_id].push_back(timestamp);
82 
83  // Append this new feature into our database
84  features_idlookup[id] = feat;
85 }
86 
87 std::vector<std::shared_ptr<Feature>> FeatureDatabase::features_not_containing_newer(double timestamp, bool remove, bool skip_deleted) {
88 
89  // Our vector of features that do not have measurements after the specified time
90  std::vector<std::shared_ptr<Feature>> feats_old;
91 
92  // Now lets loop through all features, and just make sure they are not old
93  std::lock_guard<std::mutex> lck(mtx);
94  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
95  // Skip if already deleted
96  if (skip_deleted && (*it).second->to_delete) {
97  it++;
98  continue;
99  }
100  // Loop through each camera
101  // If we have a measurement greater-than or equal to the specified, this measurement is find
102  bool has_newer_measurement = false;
103  for (auto const &pair : (*it).second->timestamps) {
104  has_newer_measurement = (!pair.second.empty() && pair.second.at(pair.second.size() - 1) >= timestamp);
105  if (has_newer_measurement) {
106  break;
107  }
108  }
109  // If it is not being actively tracked, then it is old
110  if (!has_newer_measurement) {
111  feats_old.push_back((*it).second);
112  if (remove)
113  features_idlookup.erase(it++);
114  else
115  it++;
116  } else {
117  it++;
118  }
119  }
120 
121  // Debugging
122  // PRINT_DEBUG("feature db size = %u\n", features_idlookup.size())
123 
124  // Return the old features
125  return feats_old;
126 }
127 
128 std::vector<std::shared_ptr<Feature>> FeatureDatabase::features_containing_older(double timestamp, bool remove, bool skip_deleted) {
129 
130  // Our vector of old features
131  std::vector<std::shared_ptr<Feature>> feats_old;
132 
133  // Now lets loop through all features, and just make sure they are not old
134  std::lock_guard<std::mutex> lck(mtx);
135  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
136  // Skip if already deleted
137  if (skip_deleted && (*it).second->to_delete) {
138  it++;
139  continue;
140  }
141  // Loop through each camera
142  // Check if we have at least one time older then the requested
143  bool found_containing_older = false;
144  for (auto const &pair : (*it).second->timestamps) {
145  found_containing_older = (!pair.second.empty() && pair.second.at(0) < timestamp);
146  if (found_containing_older) {
147  break;
148  }
149  }
150  // If it has an older timestamp, then add it
151  if (found_containing_older) {
152  feats_old.push_back((*it).second);
153  if (remove)
154  features_idlookup.erase(it++);
155  else
156  it++;
157  } else {
158  it++;
159  }
160  }
161 
162  // Debugging
163  // PRINT_DEBUG("feature db size = %u\n", features_idlookup.size())
164 
165  // Return the old features
166  return feats_old;
167 }
168 
169 std::vector<std::shared_ptr<Feature>> FeatureDatabase::features_containing(double timestamp, bool remove, bool skip_deleted) {
170 
171  // Our vector of old features
172  std::vector<std::shared_ptr<Feature>> feats_has_timestamp;
173 
174  // Now lets loop through all features, and just make sure they are not
175  std::lock_guard<std::mutex> lck(mtx);
176  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
177  // Skip if already deleted
178  if (skip_deleted && (*it).second->to_delete) {
179  it++;
180  continue;
181  }
182  // Boolean if it has the timestamp
183  // Break out if we found a single timestamp that is equal to the specified time
184  bool has_timestamp = false;
185  for (auto const &pair : (*it).second->timestamps) {
186  has_timestamp = (std::find(pair.second.begin(), pair.second.end(), timestamp) != pair.second.end());
187  if (has_timestamp) {
188  break;
189  }
190  }
191  // Remove this feature if it contains the specified timestamp
192  if (has_timestamp) {
193  feats_has_timestamp.push_back((*it).second);
194  if (remove)
195  features_idlookup.erase(it++);
196  else
197  it++;
198  } else {
199  it++;
200  }
201  }
202 
203  // Debugging
204  // PRINT_DEBUG("feature db size = %u\n", features_idlookup.size())
205  // PRINT_DEBUG("return vector = %u\n", feats_has_timestamp.size())
206 
207  // Return the features
208  return feats_has_timestamp;
209 }
210 
212  // Loop through all features
213  // int sizebefore = (int)features_idlookup.size();
214  std::lock_guard<std::mutex> lck(mtx);
215  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
216  // If delete flag is set, then delete it
217  if ((*it).second->to_delete) {
218  features_idlookup.erase(it++);
219  } else {
220  it++;
221  }
222  }
223  // PRINT_DEBUG("feat db = %d -> %d\n", sizebefore, (int)features_idlookup.size() << std::endl;
224 }
225 
227  std::lock_guard<std::mutex> lck(mtx);
228  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
229  // Remove the older measurements
230  (*it).second->clean_older_measurements(timestamp);
231  // Count how many measurements
232  int ct_meas = 0;
233  for (const auto &pair : (*it).second->timestamps) {
234  ct_meas += (int)(pair.second.size());
235  }
236  // If delete flag is set, then delete it
237  if (ct_meas < 1) {
238  features_idlookup.erase(it++);
239  } else {
240  it++;
241  }
242  }
243 }
244 
246  std::lock_guard<std::mutex> lck(mtx);
247  std::vector<double> timestamps = {timestamp};
248  for (auto it = features_idlookup.begin(); it != features_idlookup.end();) {
249  // Remove the older measurements
250  (*it).second->clean_invalid_measurements(timestamps);
251  // Count how many measurements
252  int ct_meas = 0;
253  for (const auto &pair : (*it).second->timestamps) {
254  ct_meas += (int)(pair.second.size());
255  }
256  // If delete flag is set, then delete it
257  if (ct_meas < 1) {
258  features_idlookup.erase(it++);
259  } else {
260  it++;
261  }
262  }
263 }
264 
266  std::lock_guard<std::mutex> lck(mtx);
267  double oldest_time = -1;
268  for (auto const &feat : features_idlookup) {
269  for (auto const &camtimepair : feat.second->timestamps) {
270  if (!camtimepair.second.empty() && (oldest_time == -1 || oldest_time > camtimepair.second.at(0))) {
271  oldest_time = camtimepair.second.at(0);
272  }
273  }
274  }
275  return oldest_time;
276 }
277 
278 void FeatureDatabase::append_new_measurements(const std::shared_ptr<FeatureDatabase> &database) {
279  std::lock_guard<std::mutex> lck(mtx);
280 
281  // Loop through the other database's internal database
282  // int sizebefore = (int)features_idlookup.size();
283  for (const auto &feat : database->get_internal_data()) {
284  if (features_idlookup.find(feat.first) != features_idlookup.end()) {
285 
286  // For this feature, now try to append the new measurement data
287  std::shared_ptr<Feature> temp = features_idlookup.at(feat.first);
288  for (const auto &times : feat.second->timestamps) {
289  // Append the whole camera vector is not seen
290  // Otherwise need to loop through each and append
291  size_t cam_id = times.first;
292  if (temp->timestamps.find(cam_id) == temp->timestamps.end()) {
293  temp->timestamps[cam_id] = feat.second->timestamps.at(cam_id);
294  temp->uvs[cam_id] = feat.second->uvs.at(cam_id);
295  temp->uvs_norm[cam_id] = feat.second->uvs_norm.at(cam_id);
296  } else {
297  auto temp_times = temp->timestamps.at(cam_id);
298  for (size_t i = 0; i < feat.second->timestamps.at(cam_id).size(); i++) {
299  double time_to_find = feat.second->timestamps.at(cam_id).at(i);
300  if (std::find(temp_times.begin(), temp_times.end(), time_to_find) == temp_times.end()) {
301  temp->timestamps.at(cam_id).push_back(feat.second->timestamps.at(cam_id).at(i));
302  temp->uvs.at(cam_id).push_back(feat.second->uvs.at(cam_id).at(i));
303  temp->uvs_norm.at(cam_id).push_back(feat.second->uvs_norm.at(cam_id).at(i));
304  }
305  }
306  }
307  }
308 
309  } else {
310 
311  // Else we have not found the feature, so lets make it be a new one!
312  std::shared_ptr<Feature> temp = std::make_shared<Feature>();
313  temp->featid = feat.second->featid;
314  temp->timestamps = feat.second->timestamps;
315  temp->uvs = feat.second->uvs;
316  temp->uvs_norm = feat.second->uvs_norm;
317  features_idlookup[feat.first] = temp;
318  }
319  }
320  // PRINT_DEBUG("feat db = %d -> %d\n", sizebefore, (int)features_idlookup.size() << std::endl;
321 }
FeatureDatabase.h
ov_core::FeatureDatabase::get_oldest_timestamp
double get_oldest_timestamp()
Gets the oldest time in the database.
Definition: FeatureDatabase.cpp:265
ov_core::FeatureDatabase::append_new_measurements
void append_new_measurements(const std::shared_ptr< FeatureDatabase > &database)
Will update the passed database with this database's latest feature information.
Definition: FeatureDatabase.cpp:278
ov_core::Feature::anchor_cam_id
int anchor_cam_id
What camera ID our pose is anchored in!! By default the first measurement is the anchor.
Definition: Feature.h:58
ov_core::FeatureDatabase::features_containing_older
std::vector< std::shared_ptr< Feature > > features_containing_older(double timestamp, bool remove=false, bool skip_deleted=false)
Get features that has measurements older then the specified time.
Definition: FeatureDatabase.cpp:128
ov_core::FeatureDatabase::size
size_t size()
Returns the size of the feature database.
Definition: FeatureDatabase.h:138
Feature.h
ov_core::FeatureDatabase::cleanup
void cleanup()
This function will delete all features that have been used up.
Definition: FeatureDatabase.cpp:211
ov_core::FeatureDatabase::features_not_containing_newer
std::vector< std::shared_ptr< Feature > > features_not_containing_newer(double timestamp, bool remove=false, bool skip_deleted=false)
Get features that do not have newer measurement then the specified time.
Definition: FeatureDatabase.cpp:87
ov_core::Feature::uvs
std::unordered_map< size_t, std::vector< Eigen::VectorXf > > uvs
UV coordinates that this feature has been seen from (mapped by camera ID)
Definition: Feature.h:49
ov_core::FeatureDatabase::mtx
std::mutex mtx
Mutex lock for our map.
Definition: FeatureDatabase.h:163
ov_core::Feature::p_FinG
Eigen::Vector3d p_FinG
Triangulated position of this feature, in the global frame.
Definition: Feature.h:67
ov_core::Feature::anchor_clone_timestamp
double anchor_clone_timestamp
Timestamp of anchor clone.
Definition: Feature.h:61
print.h
ov_core::Feature::uvs_norm
std::unordered_map< size_t, std::vector< Eigen::VectorXf > > uvs_norm
UV normalized coordinates that this feature has been seen from (mapped by camera ID)
Definition: Feature.h:52
ov_core::FeatureDatabase::cleanup_measurements_exact
void cleanup_measurements_exact(double timestamp)
This function will delete all feature measurements that are at the specified timestamp.
Definition: FeatureDatabase.cpp:245
ov_core::Feature
Sparse feature class used to collect measurements.
Definition: Feature.h:39
ov_core::Feature::featid
size_t featid
Unique ID of this feature.
Definition: Feature.h:43
ov_core::Feature::timestamps
std::unordered_map< size_t, std::vector< double > > timestamps
Timestamps of each UV measurement (mapped by camera ID)
Definition: Feature.h:55
ov_core::Feature::p_FinA
Eigen::Vector3d p_FinA
Triangulated position of this feature, in the anchor frame.
Definition: Feature.h:64
ov_core::Feature::to_delete
bool to_delete
If this feature should be deleted.
Definition: Feature.h:46
ov_core::FeatureDatabase::features_containing
std::vector< std::shared_ptr< Feature > > features_containing(double timestamp, bool remove=false, bool skip_deleted=false)
Get features that has measurements at the specified time.
Definition: FeatureDatabase.cpp:169
ov_core::FeatureDatabase::update_feature
void update_feature(size_t id, double timestamp, size_t cam_id, float u, float v, float u_n, float v_n)
Update a feature object.
Definition: FeatureDatabase.cpp:59
ov_core::FeatureDatabase::get_feature_clone
bool get_feature_clone(size_t id, Feature &feat)
Get a specified feature clone (pointer is thread safe)
Definition: FeatureDatabase.cpp:41
ov_core
Core algorithms for OpenVINS.
Definition: CamBase.h:30
ov_core::FeatureDatabase::features_idlookup
std::unordered_map< size_t, std::shared_ptr< Feature > > features_idlookup
Our lookup array that allow use to query based on ID.
Definition: FeatureDatabase.h:166
ov_core::FeatureDatabase::cleanup_measurements
void cleanup_measurements(double timestamp)
This function will delete all feature measurements that are older then the specified timestamp.
Definition: FeatureDatabase.cpp:226
ov_core::FeatureDatabase::get_feature
std::shared_ptr< Feature > get_feature(size_t id, bool remove=false)
Get a specified feature.
Definition: FeatureDatabase.cpp:29


ov_core
Author(s): Patrick Geneva , Kevin Eckenhoff , Guoquan Huang
autogenerated on Mon Jan 22 2024 03:08:17