cpp-toolbox  0.0.1
A toolbox library for C++
Loading...
Searching...
No Matches
kitti_impl.hpp
Go to the documentation of this file.
1#pragma once
2
11#include <cpp-toolbox/io/formats/kitti.hpp> // Include the header declaring the class
12
13// Add necessary includes for the implementations below
14#include <algorithm> // std::clamp
15#include <cmath> // std::is_floating_point_v, std::is_integral_v
16#include <cstdint> // INT64_C
17#include <cstring> // memcpy
18#include <fstream> // ofstream (for writing), istream
19#include <iomanip> // setprecision, fixed
20#include <limits> // numeric_limits
21#include <memory>
22#include <stdexcept> // exceptions for parsing
23#include <type_traits> // is_same_v, decay_t
24#include <vector>
25
26#include <cpp-toolbox/file/memory_mapped_file.hpp> // For reading binary
27#include <cpp-toolbox/logger/thread_logger.hpp> // For LOG_*
28// #include <cpp-toolbox/types/point.hpp> // Should be included via kitti.hpp
29
30namespace toolbox::io
31{
32
33// Assuming kitti.hpp includes this file *after* the full class definition.
34
60template<typename T>
61bool kitti_format_t::write_internal(const std::string& path,
62 const point_cloud_t<T>& cloud,
63 bool binary) const
64{
65 // KITTI格式总是二进制,忽略binary参数
66 // KITTI format is always binary, ignore binary parameter
67 LOG_DEBUG_S << "kitti_format_t::write_internal processing " << cloud.size()
68 << " points for " << path;
69
70 std::ofstream file;
71 std::ios_base::openmode mode = std::ios::trunc | std::ios::binary;
72 file.open(path, mode);
73
74 if (!file.is_open()) {
75 LOG_ERROR_S << "kitti_format_t: Failed to open file for writing: " << path;
76 return false;
77 }
78
79 // 检查点云是否为空
80 // Check if point cloud is empty
81 if (cloud.empty()) {
82 LOG_WARN_S << "kitti_format_t: Writing empty point cloud to " << path;
83 return file.good(); // 成功写入空文件/Successfully wrote empty file
84 }
85
86 // KITTI格式:每个点由4个float组成 (x, y, z, intensity)
87 // KITTI format: each point consists of 4 floats (x, y, z, intensity)
88 const size_t point_step =
89 4 * sizeof(float); // 每个点16字节/16 bytes per point
90 std::vector<unsigned char> point_buffer(point_step);
91
92 for (size_t i = 0; i < cloud.size(); ++i) {
93 unsigned char* current_ptr = point_buffer.data();
94
95 // 写入XYZ坐标/Write XYZ coordinates
96 float x_val = static_cast<float>(cloud.points[i].x);
97 float y_val = static_cast<float>(cloud.points[i].y);
98 float z_val = static_cast<float>(cloud.points[i].z);
99
100 // 写入强度值(如果没有,使用默认值0.0f)
101 // Write intensity value (use default 0.0f if not available)
102 float intensity_val = 0.0f;
103
104 std::memcpy(current_ptr, &x_val, sizeof(float));
105 current_ptr += sizeof(float);
106 std::memcpy(current_ptr, &y_val, sizeof(float));
107 current_ptr += sizeof(float);
108 std::memcpy(current_ptr, &z_val, sizeof(float));
109 current_ptr += sizeof(float);
110 std::memcpy(current_ptr, &intensity_val, sizeof(float));
111
112 file.write(reinterpret_cast<const char*>(point_buffer.data()),
113 point_buffer.size());
114 if (!file) {
115 LOG_ERROR_S << "kitti_format_t: Error writing binary data point " << i
116 << " to " << path;
117 return false;
118 }
119 }
120
121 return file.good();
122}
123
140template<typename T>
141bool kitti_format_t::read_binary_data(const std::string& path,
142 point_cloud_t<T>& cloud)
143{
145 if (!mapped_file.open(path)) {
146 LOG_ERROR_S << "kitti_format_t: Failed to memory map file: " << path;
147 return false;
148 }
149
150 const unsigned char* buffer_start = mapped_file.data();
151 if (!buffer_start) {
152 LOG_ERROR_S << "kitti_format_t: Memory mapped buffer is null for: " << path;
153 return false;
154 }
155
156 const unsigned char* buffer_end = buffer_start + mapped_file.size();
157
158 // 计算点的数量:文件大小除以每个点的大小(4个float = 16字节)
159 // Calculate number of points: file size divided by size per point (4 floats =
160 // 16 bytes)
161 const size_t point_step =
162 4 * sizeof(float); // 每个点16字节/16 bytes per point
163 const size_t num_points = mapped_file.size() / point_step;
164
165 if (mapped_file.size() % point_step != 0) {
166 LOG_WARN_S << "kitti_format_t: File size " << mapped_file.size()
167 << " is not a multiple of point size " << point_step
168 << ". Some data may be truncated.";
169 }
170
171 if (num_points == 0) {
172 LOG_WARN_S << "kitti_format_t: No points found in file: " << path;
173 return true; // 成功读取了空文件/Successfully read empty file
174 }
175
176 // 预分配内存
177 // Pre-allocate memory
178 cloud.points.reserve(num_points);
179
180 // 读取每个点的数据
181 // Read data for each point
182 for (size_t i = 0; i < num_points; ++i) {
183 const unsigned char* current_point_ptr = buffer_start + i * point_step;
184
185 // 确保不会读取超出缓冲区的数据
186 // Ensure we don't read past the buffer boundary
187 if (current_point_ptr + point_step > buffer_end) {
188 LOG_ERROR_S << "kitti_format_t: Attempt to read past mapped buffer "
189 << "boundary at point index " << i;
190 return false;
191 }
192
193 // 读取XYZ和强度值
194 // Read XYZ and intensity values
195 float x_val, y_val, z_val, intensity_val;
196 std::memcpy(&x_val, current_point_ptr, sizeof(float));
197 std::memcpy(&y_val, current_point_ptr + sizeof(float), sizeof(float));
198 std::memcpy(&z_val, current_point_ptr + 2 * sizeof(float), sizeof(float));
199 std::memcpy(
200 &intensity_val, current_point_ptr + 3 * sizeof(float), sizeof(float));
201
202 // 添加点到点云
203 // Add point to point cloud
204 point_t<T> current_point;
205 current_point.x = static_cast<T>(x_val);
206 current_point.y = static_cast<T>(y_val);
207 current_point.z = static_cast<T>(z_val);
208 cloud.points.push_back(current_point);
209
210 // 设置强度值(如果需要)
211 // Set intensity value (if needed)
212 cloud.intensity = static_cast<T>(intensity_val);
213 }
214
215 LOG_DEBUG_S << "kitti_format_t: Successfully read " << cloud.size()
216 << " points from " << path;
217
218 return true;
219}
220
221template<typename T>
222CPP_TOOLBOX_EXPORT std::unique_ptr<toolbox::types::point_cloud_t<T>>
223read_kitti_bin(const std::string& path)
224{
225 auto kitti = std::make_unique<toolbox::io::kitti_format_t>();
226 std::unique_ptr<base_file_data_t> base_data =
227 nullptr; // Create ptr of the type expected by read()
228
229 // Call read, passing the base class unique_ptr reference
230 bool success = kitti->read(path, base_data);
231
232 if (success && base_data) {
233 // Read succeeded, now check if the actual data type matches T
234 auto* typed_ptr = dynamic_cast<point_cloud_t<T>*>(base_data.get());
235 if (typed_ptr) {
236 // Type matches T, transfer ownership to a new
237 // unique_ptr<point_cloud_t<T>>
238 base_data.release(); // Prevent base_data from deleting the object
239 return std::unique_ptr<point_cloud_t<T>>(typed_ptr);
240 } else {
241 // Read succeeded, but the resulting type is not point_cloud_t<T>
242 // (e.g., read always returns float, but T was double)
244 << "read_kitti_bin: read data type does not match requested type T="
245 << typeid(T).name() << ". Path: " << path;
246 // Return nullptr as the requested type couldn't be provided.
247 // The base_data unique_ptr will delete the object when it goes out of
248 // scope.
249 return nullptr;
250 }
251 }
252
253 // Read failed or returned null data
254 return nullptr;
255}
256
257template<typename T>
258CPP_TOOLBOX_EXPORT bool write_kitti_bin(
259 const std::string& path, const toolbox::types::point_cloud_t<T>& cloud)
260{
261 auto kitti = std::make_unique<toolbox::io::kitti_format_t>();
262
263 // Create a copy of the input cloud to satisfy the unique_ptr interface
264 auto cloud_copy_ptr =
265 std::make_unique<toolbox::types::point_cloud_t<T>>(cloud);
266
267 // Cast the unique_ptr holding the copy to the base class type unique_ptr
268 std::unique_ptr<base_file_data_t> base_data_ptr = std::move(cloud_copy_ptr);
269
270 // Pass the unique_ptr (as const reference) to the write method
271 // KITTI格式总是二进制/KITTI format is always binary
272 return kitti->write(path, base_data_ptr, true);
273}
274
275} // namespace toolbox::io
RAII wrapper for memory-mapped files. / 内存映射文件的 RAII 封装。
Definition memory_mapped_file.hpp:74
size_t size() const
Gets the size of the mapped file. / 获取映射文件的大小。
Definition memory_mapped_file.hpp:237
bool open(const std::filesystem::path &path)
Opens and memory-maps the specified file. / 打开并内存映射指定的文件。
const unsigned char * data() const
Gets a pointer to the mapped memory region. / 获取指向映射内存区域的指针。
Definition memory_mapped_file.hpp:214
包含点和相关数据的点云类 / A point cloud class containing points and associated data
Definition point.hpp:268
#define LOG_DEBUG_S
DEBUG级别流式日志的宏 / Macro for DEBUG level stream logging.
Definition thread_logger.hpp:1329
#define LOG_ERROR_S
ERROR级别流式日志的宏 / Macro for ERROR level stream logging.
Definition thread_logger.hpp:1332
#define LOG_WARN_S
WARN级别流式日志的宏 / Macro for WARN level stream logging.
Definition thread_logger.hpp:1331
< 用于列出目录下的文件/For listing files in a directory
Definition dataloader.hpp:15
CPP_TOOLBOX_EXPORT bool write_kitti_bin(const std::string &path, const toolbox::types::point_cloud_t< T > &cloud)
将点云数据写入 KITTI 点云文件的独立函数。/Standalone function to write point cloud data to a KITTI point cloud file.
Definition kitti_impl.hpp:258
CPP_TOOLBOX_EXPORT std::unique_ptr< toolbox::types::point_cloud_t< T > > read_kitti_bin(const std::string &path)
从文件中读取 KITTI 点云数据的独立函数。/Standalone function to read KITTI point cloud data from a file.
Definition kitti_impl.hpp:223
std::vector< typename TContainer::value_type > mode(const TContainer &data)
计算容器中元素的众数(可能有多个)/Compute the mode(s) of elements in a container (may be multiple)
Definition statistics.hpp:138