forked from gaoxiang12/faster-lio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathivox3d.h
310 lines (261 loc) · 11.5 KB
/
ivox3d.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
//
// Created by xiang on 2021/9/16.
//
#ifndef FASTER_LIO_IVOX3D_H
#define FASTER_LIO_IVOX3D_H
#include <glog/logging.h>
#include <execution>
#include <list>
#include <thread>
#include "eigen_types.h"
#include "ivox3d_node.hpp"
namespace faster_lio {
enum class IVoxNodeType {
DEFAULT, // linear ivox
PHC, // phc ivox
};
/// traits for NodeType
// 根据 IVoxNodeType 枚举的不同值来特化结构体 IVoxNodeTypeTraits
template <IVoxNodeType node_type, typename PointT, int dim>
struct IVoxNodeTypeTraits {};
template <typename PointT, int dim>
struct IVoxNodeTypeTraits<IVoxNodeType::DEFAULT, PointT, dim> {
using NodeType = IVoxNode<PointT, dim>;
};
template <typename PointT, int dim>
struct IVoxNodeTypeTraits<IVoxNodeType::PHC, PointT, dim> {
using NodeType = IVoxNodePhc<PointT, dim>;
};
template <int dim = 3, IVoxNodeType node_type = IVoxNodeType::DEFAULT, typename PointType = pcl::PointXYZ>
class IVox {
public:
using KeyType = Eigen::Matrix<int, dim, 1>;
using PtType = Eigen::Matrix<float, dim, 1>;
using NodeType = typename IVoxNodeTypeTraits<node_type, PointType, dim>::NodeType; // 节点类型,IVoxNode 或者 IVoxNodePhc
using PointVector = std::vector<PointType, Eigen::aligned_allocator<PointType>>;
using DistPoint = typename NodeType::DistPoint;
enum class NearbyType {
CENTER, // center only
NEARBY6,
NEARBY18,
NEARBY26,
};
struct Options {
float resolution_ = 0.2; // ivox resolution //ivox的分辨率
float inv_resolution_ = 10.0; // inverse resolution //分辨率的倒数
NearbyType nearby_type_ = NearbyType::NEARBY6; // nearby range //最近邻类型
std::size_t capacity_ = 1000000; // capacity //容量
};
/**
* constructor
* @param options ivox options
*/
explicit IVox(Options options) : options_(options) {
options_.inv_resolution_ = 1.0 / options_.resolution_;
GenerateNearbyGrids();
}
/**
* add points
* @param points_to_add
*/
void AddPoints(const PointVector& points_to_add);
/// get nn
bool GetClosestPoint(const PointType& pt, PointType& closest_pt);
/// get nn with condition //带条件获取最近邻
bool GetClosestPoint(const PointType& pt, PointVector& closest_pt, int max_num = 5, double max_range = 5.0);
/// get nn in cloud //从 PointVector 中获取最近邻的 PointVector
bool GetClosestPoint(const PointVector& cloud, PointVector& closest_cloud);
/// get number of points
size_t NumPoints() const;
/// get number of valid grids //获取有效网格的数量
size_t NumValidGrids() const;
/// get statistics of the points //获取点数的统计数据
std::vector<float> StatGridPoints() const;
private:
/// generate the nearby grids according to the given options //根据给定的选项生成附近的网格
void GenerateNearbyGrids();
/// position to grid //根据点定位到网格
KeyType Pos2Grid(const PtType& pt) const;
Options options_;
std::unordered_map<KeyType, typename std::list<std::pair<KeyType, NodeType>>::iterator, hash_vec<dim>>
grids_map_; // voxel hash map
std::list<std::pair<KeyType, NodeType>> grids_cache_; // voxel cache //键和节点的缓存
std::vector<KeyType> nearby_grids_; // nearbys //周围的网格
};
// 返回最近点
template <int dim, IVoxNodeType node_type, typename PointType>
bool IVox<dim, node_type, PointType>::GetClosestPoint(const PointType& pt, PointType& closest_pt) {
std::vector<DistPoint> candidates;
auto key = Pos2Grid(ToEigen<float, dim>(pt));
std::for_each(nearby_grids_.begin(), nearby_grids_.end(), [&key, &candidates, &pt, this](const KeyType& delta) {
auto dkey = key + delta;
auto iter = grids_map_.find(dkey);
if (iter != grids_map_.end()) {
DistPoint dist_point;
bool found = iter->second->second.NNPoint(pt, dist_point);
if (found) {
candidates.emplace_back(dist_point);
}
}
});
if (candidates.empty()) {
return false;
}
auto iter = std::min_element(candidates.begin(), candidates.end());
closest_pt = iter->Get();
return true;
}
template <int dim, IVoxNodeType node_type, typename PointType>
bool IVox<dim, node_type, PointType>::GetClosestPoint(const PointType& pt, PointVector& closest_pt, int max_num,
double max_range) {
std::vector<DistPoint> candidates;
candidates.reserve(max_num * nearby_grids_.size());
auto key = Pos2Grid(ToEigen<float, dim>(pt));
// #define INNER_TIMER
#ifdef INNER_TIMER
static std::unordered_map<std::string, std::vector<int64_t>> stats;
if (stats.empty()) {
stats["knn"] = std::vector<int64_t>();
stats["nth"] = std::vector<int64_t>();
}
#endif
for (const KeyType& delta : nearby_grids_) {
auto dkey = key + delta;
auto iter = grids_map_.find(dkey);
if (iter != grids_map_.end()) {
#ifdef INNER_TIMER
auto t1 = std::chrono::high_resolution_clock::now();
#endif
auto tmp = iter->second->second.KNNPointByCondition(candidates, pt, max_num, max_range);
#ifdef INNER_TIMER
auto t2 = std::chrono::high_resolution_clock::now();
auto knn = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
stats["knn"].emplace_back(knn);
#endif
}
}
if (candidates.empty()) {
return false;
}
#ifdef INNER_TIMER
auto t1 = std::chrono::high_resolution_clock::now();
#endif
if (candidates.size() <= max_num) {
} else {
std::nth_element(candidates.begin(), candidates.begin() + max_num - 1, candidates.end());
candidates.resize(max_num);
}
std::nth_element(candidates.begin(), candidates.begin(), candidates.end());
#ifdef INNER_TIMER
auto t2 = std::chrono::high_resolution_clock::now();
auto nth = std::chrono::duration_cast<std::chrono::nanoseconds>(t2 - t1).count();
stats["nth"].emplace_back(nth);
constexpr int STAT_PERIOD = 100000;
if (!stats["nth"].empty() && stats["nth"].size() % STAT_PERIOD == 0) {
for (auto& it : stats) {
const std::string& key = it.first;
std::vector<int64_t>& stat = it.second;
int64_t sum_ = std::accumulate(stat.begin(), stat.end(), 0);
int64_t num_ = stat.size();
stat.clear();
std::cout << "inner_" << key << "(ns): sum=" << sum_ << " num=" << num_ << " ave=" << 1.0 * sum_ / num_
<< " ave*n=" << 1.0 * sum_ / STAT_PERIOD << std::endl;
}
}
#endif
closest_pt.clear();
for (auto& it : candidates) {
closest_pt.emplace_back(it.Get());
}
return closest_pt.empty() == false;
}
template <int dim, IVoxNodeType node_type, typename PointType>
size_t IVox<dim, node_type, PointType>::NumValidGrids() const {
return grids_map_.size();
}
template <int dim, IVoxNodeType node_type, typename PointType>
void IVox<dim, node_type, PointType>::GenerateNearbyGrids() {
if (options_.nearby_type_ == NearbyType::CENTER) {
nearby_grids_.emplace_back(KeyType::Zero());
} else if (options_.nearby_type_ == NearbyType::NEARBY6) {
nearby_grids_ = {KeyType(0, 0, 0), KeyType(-1, 0, 0), KeyType(1, 0, 0), KeyType(0, 1, 0),
KeyType(0, -1, 0), KeyType(0, 0, -1), KeyType(0, 0, 1)};
} else if (options_.nearby_type_ == NearbyType::NEARBY18) {
nearby_grids_ = {KeyType(0, 0, 0), KeyType(-1, 0, 0), KeyType(1, 0, 0), KeyType(0, 1, 0),
KeyType(0, -1, 0), KeyType(0, 0, -1), KeyType(0, 0, 1), KeyType(1, 1, 0),
KeyType(-1, 1, 0), KeyType(1, -1, 0), KeyType(-1, -1, 0), KeyType(1, 0, 1),
KeyType(-1, 0, 1), KeyType(1, 0, -1), KeyType(-1, 0, -1), KeyType(0, 1, 1),
KeyType(0, -1, 1), KeyType(0, 1, -1), KeyType(0, -1, -1)};
} else if (options_.nearby_type_ == NearbyType::NEARBY26) {
nearby_grids_ = {KeyType(0, 0, 0), KeyType(-1, 0, 0), KeyType(1, 0, 0), KeyType(0, 1, 0),
KeyType(0, -1, 0), KeyType(0, 0, -1), KeyType(0, 0, 1), KeyType(1, 1, 0),
KeyType(-1, 1, 0), KeyType(1, -1, 0), KeyType(-1, -1, 0), KeyType(1, 0, 1),
KeyType(-1, 0, 1), KeyType(1, 0, -1), KeyType(-1, 0, -1), KeyType(0, 1, 1),
KeyType(0, -1, 1), KeyType(0, 1, -1), KeyType(0, -1, -1), KeyType(1, 1, 1),
KeyType(-1, 1, 1), KeyType(1, -1, 1), KeyType(1, 1, -1), KeyType(-1, -1, 1),
KeyType(-1, 1, -1), KeyType(1, -1, -1), KeyType(-1, -1, -1)};
} else {
LOG(ERROR) << "Unknown nearby_type!";
}
}
template <int dim, IVoxNodeType node_type, typename PointType>
bool IVox<dim, node_type, PointType>::GetClosestPoint(const PointVector& cloud, PointVector& closest_cloud) {
std::vector<size_t> index(cloud.size());
for (int i = 0; i < cloud.size(); ++i) {
index[i] = i;
}
closest_cloud.resize(cloud.size());
std::for_each(std::execution::par_unseq, index.begin(), index.end(), [&cloud, &closest_cloud, this](size_t idx) {
PointType pt;
if (GetClosestPoint(cloud[idx], pt)) {
closest_cloud[idx] = pt;
} else {
closest_cloud[idx] = PointType();
}
});
return true;
}
template <int dim, IVoxNodeType node_type, typename PointType>
void IVox<dim, node_type, PointType>::AddPoints(const PointVector& points_to_add) {
std::for_each(std::execution::unseq, points_to_add.begin(), points_to_add.end(), [this](const auto& pt) {
auto key = Pos2Grid(ToEigen<float, dim>(pt));
auto iter = grids_map_.find(key);
if (iter == grids_map_.end()) {
PointType center;
center.getVector3fMap() = key.template cast<float>() * options_.resolution_;
grids_cache_.push_front({key, NodeType(center, options_.resolution_)});
grids_map_.insert({key, grids_cache_.begin()});
grids_cache_.front().second.InsertPoint(pt);
if (grids_map_.size() >= options_.capacity_) {
grids_map_.erase(grids_cache_.back().first);
grids_cache_.pop_back();
}
} else {
iter->second->second.InsertPoint(pt);
grids_cache_.splice(grids_cache_.begin(), grids_cache_, iter->second);
grids_map_[key] = grids_cache_.begin();
}
});
}
template <int dim, IVoxNodeType node_type, typename PointType>
Eigen::Matrix<int, dim, 1> IVox<dim, node_type, PointType>::Pos2Grid(const IVox::PtType& pt) const {
return (pt * options_.inv_resolution_).array().round().template cast<int>();
}
template <int dim, IVoxNodeType node_type, typename PointType>
std::vector<float> IVox<dim, node_type, PointType>::StatGridPoints() const {
int num = grids_cache_.size(), valid_num = 0, max = 0, min = 100000000;
int sum = 0, sum_square = 0;
for (auto& it : grids_cache_) {
int s = it.second.Size();
valid_num += s > 0;
max = s > max ? s : max;
min = s < min ? s : min;
sum += s;
sum_square += s * s;
}
float ave = float(sum) / num;
float stddev = num > 1 ? sqrt((float(sum_square) - num * ave * ave) / (num - 1)) : 0;
return std::vector<float>{valid_num, ave, max, min, stddev};
}
} // namespace faster_lio
#endif