cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
kitti_extended_impl.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <fstream>
7#include <sstream>
8#include <algorithm>
9#include <filesystem>
10#include <iomanip>
11#include <cstring>
12#include <stdexcept>
13#include <map>
14
15namespace toolbox::io {
16
17// ==================== Label I/O Implementation ====================
18
19inline std::vector<uint32_t> read_kitti_labels(const std::string& file_path) {
20 std::vector<uint32_t> labels;
21
22 std::ifstream file(file_path, std::ios::binary | std::ios::ate);
23 if (!file.is_open()) {
24 throw std::runtime_error("Failed to open label file: " + file_path);
25 }
26
27 const auto file_size = file.tellg();
28 file.seekg(0);
29
30 if (file_size % sizeof(uint32_t) != 0) {
31 throw std::runtime_error("Label file size is not a multiple of uint32_t");
32 }
33
34 const auto num_labels = static_cast<std::size_t>(file_size) / sizeof(uint32_t);
35 labels.resize(num_labels);
36
37 file.read(reinterpret_cast<char*>(labels.data()), file_size);
38
39 if (!file) {
40 throw std::runtime_error("Failed to read labels from: " + file_path);
41 }
42
43 return labels;
44}
45
46inline bool write_kitti_labels(const std::string& file_path,
47 const std::vector<uint32_t>& labels) {
48 std::ofstream file(file_path, std::ios::binary);
49 if (!file.is_open()) {
50 return false;
51 }
52
53 file.write(reinterpret_cast<const char*>(labels.data()),
54 labels.size() * sizeof(uint32_t));
55
56 return file.good();
57}
58
59// ==================== Pose I/O Implementation ====================
60
61template<typename DataType>
62Eigen::Matrix<DataType, 4, 4> parse_kitti_pose_line(const std::string& line) {
63 std::istringstream iss(line);
64 Eigen::Matrix<DataType, 4, 4> pose = Eigen::Matrix<DataType, 4, 4>::Identity();
65
66 // Read 3x4 matrix values
67 for (int row = 0; row < 3; ++row) {
68 for (int col = 0; col < 4; ++col) {
69 DataType value;
70 if (!(iss >> value)) {
71 throw std::invalid_argument("Invalid pose format in line: " + line);
72 }
73 pose(row, col) = value;
74 }
75 }
76
77 // Last row is always [0, 0, 0, 1]
78 pose(3, 0) = 0;
79 pose(3, 1) = 0;
80 pose(3, 2) = 0;
81 pose(3, 3) = 1;
82
83 return pose;
84}
85
86template<typename DataType>
87std::vector<Eigen::Matrix<DataType, 4, 4>> read_kitti_poses(const std::string& file_path) {
88 std::vector<Eigen::Matrix<DataType, 4, 4>> poses;
89
90 std::ifstream file(file_path);
91 if (!file.is_open()) {
92 throw std::runtime_error("Failed to open poses file: " + file_path);
93 }
94
95 std::string line;
96 while (std::getline(file, line)) {
97 if (line.empty()) {
98 continue;
99 }
100
101 poses.push_back(parse_kitti_pose_line<DataType>(line));
102 }
103
104 return poses;
105}
106
107template<typename DataType>
108std::string format_kitti_pose(const Eigen::Matrix<DataType, 4, 4>& pose) {
109 std::ostringstream oss;
110 oss << std::fixed << std::setprecision(9);
111
112 // Write first 3 rows
113 for (int row = 0; row < 3; ++row) {
114 for (int col = 0; col < 4; ++col) {
115 if (row > 0 || col > 0) oss << " ";
116 oss << pose(row, col);
117 }
118 }
119
120 return oss.str();
121}
122
123template<typename DataType>
124bool write_kitti_poses(const std::string& file_path,
125 const std::vector<Eigen::Matrix<DataType, 4, 4>>& poses) {
126 std::ofstream file(file_path);
127 if (!file.is_open()) {
128 return false;
129 }
130
131 for (const auto& pose : poses) {
132 file << format_kitti_pose(pose) << "\n";
133 }
134
135 return file.good();
136}
137
138// ==================== Calibration I/O Implementation ====================
139
140template<typename DataType>
143
144 std::ifstream file(file_path);
145 if (!file.is_open()) {
146 throw std::runtime_error("Failed to open calibration file: " + file_path);
147 }
148
149 std::string line;
150 while (std::getline(file, line)) {
151 std::istringstream iss(line);
152 std::string key;
153
154 if (!(iss >> key)) continue;
155
156 // Remove the colon
157 if (!key.empty() && key.back() == ':') {
158 key.pop_back();
159 }
160
161 if (key == "P0") {
162 for (int i = 0; i < 12; ++i) {
163 iss >> calib.P0(i / 4, i % 4);
164 }
165 } else if (key == "P1") {
166 for (int i = 0; i < 12; ++i) {
167 iss >> calib.P1(i / 4, i % 4);
168 }
169 } else if (key == "P2") {
170 for (int i = 0; i < 12; ++i) {
171 iss >> calib.P2(i / 4, i % 4);
172 }
173 } else if (key == "P3") {
174 for (int i = 0; i < 12; ++i) {
175 iss >> calib.P3(i / 4, i % 4);
176 }
177 } else if (key == "R0_rect") {
178 for (int i = 0; i < 9; ++i) {
179 iss >> calib.R0_rect(i / 3, i % 3);
180 }
181 } else if (key == "Tr_velo_to_cam") {
182 for (int i = 0; i < 12; ++i) {
183 iss >> calib.Tr_velo_to_cam(i / 4, i % 4);
184 }
185 calib.Tr_velo_to_cam(3, 0) = 0;
186 calib.Tr_velo_to_cam(3, 1) = 0;
187 calib.Tr_velo_to_cam(3, 2) = 0;
188 calib.Tr_velo_to_cam(3, 3) = 1;
189 } else if (key == "Tr_imu_to_velo") {
190 Eigen::Matrix<DataType, 4, 4> imu_to_velo =
191 Eigen::Matrix<DataType, 4, 4>::Identity();
192 for (int i = 0; i < 12; ++i) {
193 iss >> imu_to_velo(i / 4, i % 4);
194 }
195 imu_to_velo(3, 0) = 0;
196 imu_to_velo(3, 1) = 0;
197 imu_to_velo(3, 2) = 0;
198 imu_to_velo(3, 3) = 1;
199 calib.Tr_imu_to_velo = imu_to_velo;
200 }
201 }
202
203 return calib;
204}
205
206template<typename DataType>
207bool write_kitti_calibration(const std::string& file_path,
208 const kitti_calibration_t<DataType>& calib) {
209 std::ofstream file(file_path);
210 if (!file.is_open()) {
211 return false;
212 }
213
214 file << std::fixed << std::setprecision(9);
215
216 // Write P0-P3
217 file << "P0: ";
218 for (int i = 0; i < 3; ++i) {
219 for (int j = 0; j < 4; ++j) {
220 if (i > 0 || j > 0) file << " ";
221 file << calib.P0(i, j);
222 }
223 }
224 file << "\n";
225
226 file << "P1: ";
227 for (int i = 0; i < 3; ++i) {
228 for (int j = 0; j < 4; ++j) {
229 if (i > 0 || j > 0) file << " ";
230 file << calib.P1(i, j);
231 }
232 }
233 file << "\n";
234
235 file << "P2: ";
236 for (int i = 0; i < 3; ++i) {
237 for (int j = 0; j < 4; ++j) {
238 if (i > 0 || j > 0) file << " ";
239 file << calib.P2(i, j);
240 }
241 }
242 file << "\n";
243
244 file << "P3: ";
245 for (int i = 0; i < 3; ++i) {
246 for (int j = 0; j < 4; ++j) {
247 if (i > 0 || j > 0) file << " ";
248 file << calib.P3(i, j);
249 }
250 }
251 file << "\n";
252
253 // Write R0_rect
254 file << "R0_rect: ";
255 for (int i = 0; i < 3; ++i) {
256 for (int j = 0; j < 3; ++j) {
257 if (i > 0 || j > 0) file << " ";
258 file << calib.R0_rect(i, j);
259 }
260 }
261 file << "\n";
262
263 // Write Tr_velo_to_cam
264 file << "Tr_velo_to_cam: ";
265 for (int i = 0; i < 3; ++i) {
266 for (int j = 0; j < 4; ++j) {
267 if (i > 0 || j > 0) file << " ";
268 file << calib.Tr_velo_to_cam(i, j);
269 }
270 }
271 file << "\n";
272
273 // Write Tr_imu_to_velo if available
274 if (calib.Tr_imu_to_velo.has_value()) {
275 file << "Tr_imu_to_velo: ";
276 for (int i = 0; i < 3; ++i) {
277 for (int j = 0; j < 4; ++j) {
278 if (i > 0 || j > 0) file << " ";
279 file << calib.Tr_imu_to_velo.value()(i, j);
280 }
281 }
282 file << "\n";
283 }
284
285 return file.good();
286}
287
288// ==================== Utility Functions Implementation ====================
289
290template<typename DataType>
291Eigen::Matrix<DataType, 4, 4> compute_relative_transform(
292 const Eigen::Matrix<DataType, 4, 4>& from_pose,
293 const Eigen::Matrix<DataType, 4, 4>& to_pose) {
294 // T_to_from = T_to_world * T_world_from = to_pose * from_pose.inverse()
295 return to_pose * from_pose.inverse();
296}
297
298template<typename DataType>
299std::unique_ptr<point_cloud_t<DataType>> transform_point_cloud(
300 const point_cloud_t<DataType>& cloud,
301 const Eigen::Matrix<DataType, 4, 4>& transform) {
302
303 auto transformed = std::make_unique<point_cloud_t<DataType>>();
304 transformed->points.reserve(cloud.points.size());
305 transformed->intensity = cloud.intensity;
306
307 for (const auto& pt : cloud.points) {
308 Eigen::Vector4d homogeneous(pt.x, pt.y, pt.z, 1.0);
309 Eigen::Vector4d transformed_pt = transform.template cast<double>() * homogeneous;
310
311 point_t<DataType> new_pt;
312 new_pt.x = static_cast<DataType>(transformed_pt[0]);
313 new_pt.y = static_cast<DataType>(transformed_pt[1]);
314 new_pt.z = static_cast<DataType>(transformed_pt[2]);
315
316 transformed->points.push_back(new_pt);
317 }
318
319 return transformed;
320}
321
322template<typename DataType>
323std::unique_ptr<point_cloud_t<DataType>> read_kitti_with_labels(
324 const std::string& bin_path,
325 const std::string& label_path,
326 std::vector<uint32_t>& labels) {
327
328 // Read point cloud
329 auto cloud = read_kitti_bin<DataType>(bin_path);
330 if (!cloud) {
331 throw std::runtime_error("Failed to read point cloud from: " + bin_path);
332 }
333
334 // Read labels
335 try {
336 labels = read_kitti_labels(label_path);
337 } catch (const std::exception& e) {
338 throw std::runtime_error("Failed to read labels from: " + label_path + ". Error: " + e.what());
339 }
340
341 // Check size consistency
342 if (cloud->size() != labels.size()) {
343 throw std::runtime_error("Point cloud size (" + std::to_string(cloud->size()) +
344 ") does not match label count (" + std::to_string(labels.size()) + ")");
345 }
346
347 return cloud;
348}
349
350inline std::vector<std::string> list_kitti_cloud_files(const std::string& velodyne_path) {
351 namespace fs = std::filesystem;
352
353 std::vector<std::string> files;
354
355 if (!fs::exists(velodyne_path)) {
356 return files;
357 }
358
359 for (const auto& entry : fs::directory_iterator(velodyne_path)) {
360 if (entry.path().extension() == ".bin") {
361 files.push_back(entry.path().string());
362 }
363 }
364
365 // Sort by filename
366 std::sort(files.begin(), files.end());
367
368 return files;
369}
370
371inline std::vector<std::string> list_kitti_label_files(const std::string& labels_path) {
372 namespace fs = std::filesystem;
373
374 std::vector<std::string> files;
375
376 if (!fs::exists(labels_path)) {
377 return files;
378 }
379
380 for (const auto& entry : fs::directory_iterator(labels_path)) {
381 if (entry.path().extension() == ".label") {
382 files.push_back(entry.path().string());
383 }
384 }
385
386 // Sort by filename
387 std::sort(files.begin(), files.end());
388
389 return files;
390}
391
392inline int parse_kitti_frame_index(const std::string& filename) {
393 namespace fs = std::filesystem;
394
395 fs::path path(filename);
396 std::string stem = path.stem().string();
397
398 try {
399 return std::stoi(stem);
400 } catch (const std::exception&) {
401 return -1;
402 }
403}
404
405inline std::string format_kitti_frame_index(std::size_t index, int digits) {
406 std::ostringstream oss;
407 oss << std::setfill('0') << std::setw(digits) << index;
408 return oss.str();
409}
410
411inline kitti_sequence_info_t get_kitti_sequence_info(const std::string& sequence_path) {
412 namespace fs = std::filesystem;
413
415 info.path = fs::path(sequence_path);
416 info.sequence_name = info.path.filename().string();
417
418 // Count velodyne files
419 fs::path velodyne_path = info.path / "velodyne";
420 if (fs::exists(velodyne_path)) {
421 info.num_frames = 0;
422 for (const auto& entry : fs::directory_iterator(velodyne_path)) {
423 if (entry.path().extension() == ".bin") {
424 info.num_frames++;
425 }
426 }
427 }
428
429 // Check for labels
430 info.has_labels = fs::exists(info.path / "labels");
431
432 // Check for calibration
433 info.has_calibration = fs::exists(info.path / "calib.txt");
434
435 return info;
436}
437
438inline bool validate_kitti_sequence_directory(const std::string& sequence_path) {
439 namespace fs = std::filesystem;
440
441 if (!fs::exists(sequence_path) || !fs::is_directory(sequence_path)) {
442 return false;
443 }
444
445 // Check for velodyne directory
446 fs::path velodyne_path = fs::path(sequence_path) / "velodyne";
447 if (!fs::exists(velodyne_path) || !fs::is_directory(velodyne_path)) {
448 return false;
449 }
450
451 return true;
452}
453
454// ==================== Label Names Implementation ====================
455
456namespace kitti_semantic_labels {
457
458inline std::string get_label_name(uint16_t label) {
459 static const std::map<uint16_t, std::string> label_names = {
460 {0, "unlabeled"},
461 {1, "outlier"},
462 {10, "car"},
463 {11, "bicycle"},
464 {13, "bus"},
465 {15, "motorcycle"},
466 {18, "truck"},
467 {20, "other-vehicle"},
468 {30, "person"},
469 {31, "bicyclist"},
470 {32, "motorcyclist"},
471 {40, "road"},
472 {44, "parking"},
473 {48, "sidewalk"},
474 {49, "other-ground"},
475 {50, "building"},
476 {51, "fence"},
477 {52, "other-structure"},
478 {70, "vegetation"},
479 {71, "trunk"},
480 {72, "terrain"},
481 {80, "pole"},
482 {81, "traffic-sign"}
483 };
484
485 auto it = label_names.find(label);
486 if (it != label_names.end()) {
487 return it->second;
488 }
489 return "unknown";
490}
491
492inline std::map<uint16_t, std::string> get_label_map() {
493 return {
494 {0, "unlabeled"},
495 {1, "outlier"},
496 {10, "car"},
497 {11, "bicycle"},
498 {13, "bus"},
499 {15, "motorcycle"},
500 {18, "truck"},
501 {20, "other-vehicle"},
502 {30, "person"},
503 {31, "bicyclist"},
504 {32, "motorcyclist"},
505 {40, "road"},
506 {44, "parking"},
507 {48, "sidewalk"},
508 {49, "other-ground"},
509 {50, "building"},
510 {51, "fence"},
511 {52, "other-structure"},
512 {70, "vegetation"},
513 {71, "trunk"},
514 {72, "terrain"},
515 {80, "pole"},
516 {81, "traffic-sign"}
517 };
518}
519
520} // namespace kitti_semantic_labels
521
522} // namespace toolbox::io
包含点和相关数据的点云类 / A point cloud class containing points and associated data
Definition point.hpp:268
std::vector< point_t< T > > points
点坐标 / Point coordinates
Definition point.hpp:270
T intensity
全局强度值 / Global intensity value
Definition point.hpp:273
std::string get_label_name(uint16_t label)
Get human-readable label name.
Definition kitti_extended_impl.hpp:458
std::map< uint16_t, std::string > get_label_map()
Get all label names mapping.
Definition kitti_extended_impl.hpp:492
< 用于列出目录下的文件/For listing files in a directory
Definition dataloader.hpp:15
std::string format_kitti_frame_index(std::size_t index, int digits)
Format frame index as KITTI filename (e.g., 123 -> "000123")
Definition kitti_extended_impl.hpp:405
bool write_kitti_labels(const std::string &file_path, const std::vector< uint32_t > &labels)
Write labels to Semantic KITTI format.
Definition kitti_extended_impl.hpp:46
kitti_calibration_t< DataType > read_kitti_calibration(const std::string &file_path)
Read KITTI calibration file.
Definition kitti_extended_impl.hpp:141
bool write_kitti_calibration(const std::string &file_path, const kitti_calibration_t< DataType > &calib)
Write KITTI calibration file.
Definition kitti_extended_impl.hpp:207
std::unique_ptr< point_cloud_t< DataType > > read_kitti_with_labels(const std::string &bin_path, const std::string &label_path, std::vector< uint32_t > &labels)
Read KITTI point cloud with semantic labels.
Definition kitti_extended_impl.hpp:323
std::vector< uint32_t > read_kitti_labels(const std::string &file_path)
Read Semantic KITTI label file.
Definition kitti_extended_impl.hpp:19
Eigen::Matrix< DataType, 4, 4 > parse_kitti_pose_line(const std::string &line)
Parse a single line from KITTI poses file.
Definition kitti_extended_impl.hpp:62
bool write_kitti_poses(const std::string &file_path, const std::vector< Eigen::Matrix< DataType, 4, 4 > > &poses)
Write poses to KITTI format file.
Definition kitti_extended_impl.hpp:124
std::string format_kitti_pose(const Eigen::Matrix< DataType, 4, 4 > &pose)
Format pose matrix as KITTI string.
Definition kitti_extended_impl.hpp:108
std::vector< std::string > list_kitti_label_files(const std::string &labels_path)
List all KITTI label files in a directory.
Definition kitti_extended_impl.hpp:371
bool validate_kitti_sequence_directory(const std::string &sequence_path)
Validate KITTI sequence directory structure.
Definition kitti_extended_impl.hpp:438
std::unique_ptr< point_cloud_t< DataType > > transform_point_cloud(const point_cloud_t< DataType > &cloud, const Eigen::Matrix< DataType, 4, 4 > &transform)
Transform point cloud using transformation matrix.
Definition kitti_extended_impl.hpp:299
kitti_sequence_info_t get_kitti_sequence_info(const std::string &sequence_path)
Get information about a KITTI sequence directory.
Definition kitti_extended_impl.hpp:411
Eigen::Matrix< DataType, 4, 4 > compute_relative_transform(const Eigen::Matrix< DataType, 4, 4 > &from_pose, const Eigen::Matrix< DataType, 4, 4 > &to_pose)
Compute relative transformation between two poses.
Definition kitti_extended_impl.hpp:291
std::vector< std::string > list_kitti_cloud_files(const std::string &velodyne_path)
List all KITTI point cloud files in a directory.
Definition kitti_extended_impl.hpp:350
std::vector< Eigen::Matrix< DataType, 4, 4 > > read_kitti_poses(const std::string &file_path)
Read all poses from KITTI poses file.
Definition kitti_extended_impl.hpp:87
int parse_kitti_frame_index(const std::string &filename)
Get frame index from KITTI filename (e.g., "000123.bin" -> 123)
Definition kitti_extended_impl.hpp:392
KITTI calibration data structure.
Definition kitti_extended.hpp:81
std::optional< Eigen::Matrix< DataType, 4, 4 > > Tr_imu_to_velo
Transformation from IMU to Velodyne.
Definition kitti_extended.hpp:92
Eigen::Matrix< DataType, 3, 4 > P3
Definition kitti_extended.hpp:86
Eigen::Matrix< DataType, 3, 4 > P1
Definition kitti_extended.hpp:86
Eigen::Matrix< DataType, 3, 4 > P0
Projection matrices for cameras 0-3 after rectification.
Definition kitti_extended.hpp:86
Eigen::Matrix< DataType, 3, 3 > R0_rect
Rectification rotation matrix for camera 0.
Definition kitti_extended.hpp:89
Eigen::Matrix< DataType, 4, 4 > Tr_velo_to_cam
Transformation from Velodyne to camera 0 rectified coordinates.
Definition kitti_extended.hpp:83
Eigen::Matrix< DataType, 3, 4 > P2
Definition kitti_extended.hpp:86
Information about a KITTI sequence.
Definition kitti_extended.hpp:206
bool has_calibration
Whether calibration file exists.
Definition kitti_extended.hpp:209
std::filesystem::path path
Full path to sequence directory.
Definition kitti_extended.hpp:211
std::size_t num_frames
Number of frames in the sequence.
Definition kitti_extended.hpp:207
bool has_labels
Whether labels directory exists.
Definition kitti_extended.hpp:208
std::string sequence_name
Sequence name (e.g., "00", "01")
Definition kitti_extended.hpp:210
3D点/向量模板类 / A 3D point/vector template class
Definition point.hpp:48
T x
X坐标 / X coordinate.
Definition point.hpp:51
T z
Z坐标 / Z coordinate.
Definition point.hpp:53
T y
Y坐标 / Y coordinate.
Definition point.hpp:52