UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
render2d.cpp
1#ifdef UFO_TBB
2// #undef UFO_TBB
3#endif
4#ifdef UFO_OMP
5// #undef UFO_OMP
6#endif
7
8// UFO
9#include <ufo/map/color/map.hpp>
10#include <ufo/map/occupancy/map.hpp>
11#include <ufo/map/ufomap.hpp>
12#include <ufo/numeric/trans2.hpp>
13#include <ufo/vision/image.hpp>
14// #include <ufo/util/timing.hpp>
15#include <ufo/execution/execution.hpp>
16#include <ufo/map/distance/map.hpp>
17#include <ufo/pcl/cloud.hpp>
18#include <ufo/vision/camera.hpp>
19
20// STL
21#include <bitset>
22#include <cstddef>
23#include <cstdint>
24#include <cstdio>
25#include <filesystem>
26#include <fstream>
27#include <future>
28#include <iostream>
29#include <limits>
30#include <random>
31#include <string>
32#include <vector>
33
34// OpenCV
35#include <opencv2/core.hpp>
36#include <opencv2/highgui.hpp>
37
38// Happly
39#include <ufo/happly.h>
40
41using namespace ufo;
42
43static Color color(double value, double min_value, double max_value, double color_factor)
44{
45 double const s = 1;
46 double const v = 1;
47
48 value = std::clamp((value - min_value) / (max_value - min_value), 0.0, 1.0);
49
50 double h = (1 - value) * color_factor;
51 h -= std::floor(h);
52 h *= 6;
53
54 int const i = std::floor(h);
55
56 double const f = (i & 1) ? h - i : 1 - (h - i);
57
58 double const m = v * (1 - s);
59
60 double const n = v * (1 - s * f);
61
62 switch (i) {
63 case 6:
64 case 0: return Color(255 * m, 255 * n, 255 * v);
65 case 1: return Color(255 * m, 255 * v, 255 * n);
66 case 2: return Color(255 * n, 255 * v, 255 * m);
67 case 3: return Color(255 * v, 255 * n, 255 * m);
68 case 4: return Color(255 * v, 255 * m, 255 * n);
69 case 5: return Color(255 * n, 255 * m, 255 * v);
70 default: return Color(255 * 0.5, 255 * 0.5, 255 * 1);
71 }
72}
73
74int main(int argc, char* argv[])
75{
76 // Vec4f v1;
77 // Vec4f v2;
78
79 // Mat4x4f m;
80 // std::cout << "Before\n" << m << '\n';
81 // std::cout << "After\n" << inverse(m) << '\n';
82 // exit(1);
83
85
86 // ufo::Timing timer;
87
88 Vec3f min(100000, 100000, 100000);
89 Vec3f max(-100000, -100000, -100000);
90
91 happly::PLYData ply_in(RESOURCE_DIR "/scene0000_00_vh_clean.ply");
92 auto v_pos = ply_in.getVertexPositions();
93 auto v_col = ply_in.getVertexColors();
94 auto f_ind = ply_in.getFaceIndices<std::size_t>();
95 std::unordered_map<QuadCode, std::pair<std::vector<Vec2f>, std::vector<Color>>> points;
96
97 auto const t1 = std::chrono::high_resolution_clock::now();
98 for (auto f : f_ind) {
99 Triangle3 t(Vec3f(v_pos[f[0]][0], v_pos[f[0]][1], v_pos[f[0]][2]),
100 Vec3f(v_pos[f[1]][0], v_pos[f[1]][1], v_pos[f[1]][2]),
101 Vec3f(v_pos[f[2]][0], v_pos[f[2]][1], v_pos[f[2]][2]));
102
103 std::array c{Color(v_col[f[0]][0], v_col[f[0]][1], v_col[f[0]][2]),
104 Color(v_col[f[1]][0], v_col[f[1]][1], v_col[f[1]][2]),
105 Color(v_col[f[2]][0], v_col[f[2]][1], v_col[f[2]][2])};
106
107 for (std::size_t i{}; 3 > i; ++i) {
108 min = ufo::min(min, t[i]);
109 max = ufo::max(max, t[i]);
110 // if (1.0f < t[i].z && 2.0 > t[i].z) {
111 auto& [a, b] = points[map.code(Vec2f(t[i]))];
112 a.emplace_back(Vec2f(t[i]));
113 b.emplace_back(c[i]);
114 // }
115 }
116 }
117
118 auto const t2 = std::chrono::high_resolution_clock::now();
119 std::chrono::duration<double, std::milli> const preprocess_ms = t2 - t1;
120
121 std::cout << std::setw(28) << std::left << "Preprocess: " << preprocess_ms.count()
122 << " ms\n";
123
124 auto f = std::async(std::launch::async, [&map, &points]() {
125 auto const t1 = std::chrono::high_resolution_clock::now();
126
127 for (auto const& [code, elem] : points) {
128 auto const& [points, colors] = elem;
129 map.occupancySet(code, 1.0, false);
130 map.colorSet(code, Color::blend(colors, ColorBlendingMode::SQ_MEAN), false);
131 Vec2f p = std::accumulate(points.begin(), points.end(), Vec2f());
132 p /= points.size();
133 map.distanceSet(code, p, points.size(), false);
134 }
135
136 auto const t2 = std::chrono::high_resolution_clock::now();
137
138 map.propagateModified();
139
140 auto const t3 = std::chrono::high_resolution_clock::now();
141 std::chrono::duration<double, std::milli> const set_ms = t2 - t1;
142 std::chrono::duration<double, std::milli> const propagate_ms = t3 - t2;
143 std::chrono::duration<double, std::milli> const total_ms = t3 - t1;
144
145 std::cout << std::setw(28) << std::left << "Set: " << set_ms.count()
146 << " ms\n";
147 std::cout << std::setw(28) << std::left << "Propagate: " << propagate_ms.count()
148 << " ms\n";
149 std::cout << std::setw(28) << std::left << "Total: " << total_ms.count()
150 << " ms\n";
151 });
152
153 f.wait();
154
155 // std::ofstream xyzrgb("/home/dduberg/ufo/xyzrgb.txt");
156 // for (auto node : map.query(pred::Leaf() && pred::Occupied())) {
157 // auto center = map.center(node.index());
158 // auto color = map.color(node.index());
159 // xyzrgb << center.x << ' ' << center.y << ' ' << 0.0f << ' ' << +color.red << ' '
160 // << +color.green << ' ' << +color.blue << '\n';
161 // }
162 // xyzrgb.close();
163
164 // std::ofstream distancergb("/home/dduberg/ufo/distancergb.txt");
165 // for (auto node : map.query(pred::Leaf() && pred::Occupied())) {
166 // auto point = map.distanceInfo(node.index()).point;
167 // auto color = map.color(node.index());
168 // distancergb << point.x << ' ' << point.y << ' ' << 0.0f << ' ' << +color.red << ' '
169 // << +color.green << ' ' << +color.blue << '\n';
170 // }
171 // distancergb.close();
172
173 // exit(0);
174
175 // std::ofstream xyzrgb("/home/dduberg/ufo/xyzrgb.txt");
176 // for (auto node : map.query(pred::Leaf() && pred::Occupied())) {
177 // auto center = map.center(node.index());
178 // auto color = map.color(node.index());
179 // xyzrgb << center.x << ' ' << center.y << ' ' << 0.0f << ' ' << +color.red << ' '
180 // << +color.green << ' ' << +color.blue << '\n';
181 // }
182 // xyzrgb.close();
183
184 auto inner_f = [&map](auto node, Ray2 /* ray */, float /* distance */) -> bool {
185 // return map.containsOccupied(node);
186 return true;
187 };
188
189 auto hit_f = [&map](auto node, Ray2 ray,
190 float distance) -> std::pair<bool, std::pair<Vec2f, Color>> {
191 float max_distance = 7.0f;
192 // return std::make_pair(map.isLeaf(node) && map.containsOccupied(node),
193 // std::make_pair(map.center(node), map.color(node)));
194
195 auto d = map.distance<false>(ray.origin);
196 Color c(255 * d / max_distance, 255 * d / max_distance, 255 * d / max_distance);
197
198 return std::make_pair(true, std::make_pair(map.center(node), c));
199 };
200
201 // Ray2 ray(Vec2f(max - min) / 2.0f, Vec2f(1, 0));
202 // for (float theta{}; 2 * numbers::pi_v<float> > theta;
203 // theta += (2 * numbers::pi_v<float>) / 360.0f) {
204 // ray.direction.x = std::cos(theta);
205 // ray.direction.y = std::sin(theta);
206
207 // auto [p, c] = map.trace(
208 // ray, inner_f, hit_f,
209 // std::make_pair(Vec2f(std::numeric_limits<float>::quiet_NaN()), Color()));
210
211 // if (std::isnan(p.x)) {
212 // continue;
213 // }
214
215 // xyzrgb << p.x << ' ' << p.y << ' ' << 0.0f << ' ' << +c.red << ' ' << +c.green << '
216 // '
217 // << +c.blue << '\n';
218 // }
219 // xyzrgb.close();
220
221 Camera camera;
222 camera.vertical_fov = radians(60.0f);
223 camera.near_clip = 0.30310887f;
224 camera.far_clip = 4.7810888f;
225 camera.projection_type = ProjectionType::PERSPECTIVE;
226
227 std::size_t rows = 720; // 360; // 720; // 1080;
228 std::size_t cols = 1280; // 640; // 1280; // 1920;
229
230 std::size_t output_rows = rows / 1;
231 std::size_t output_cols = cols / 1;
232
233 rows /= 1;
234 cols /= 1;
235
236 double fps = 90.0;
237
238 std::vector<std::size_t> row_idx(rows);
239 std::iota(row_idx.begin(), row_idx.end(), 0);
240
241 std::vector<std::size_t> output_row_idx(output_rows);
242 std::iota(output_row_idx.begin(), output_row_idx.end(), 0);
243
244 Image<std::pair<Color, Color>> image(rows, cols);
245
246 cv::Mat img(output_rows, output_cols * 2, CV_8UC3);
247
248 cv::Mat rgb(output_rows, output_cols, CV_8UC3);
249 cv::Mat mask(output_rows, output_cols, CV_8UC3);
250
251 double ufo_total_ms{};
252 double interpolate_total_ms{};
253 std::size_t iterations{};
254
255 float angle_x = 0.0f;
256 float angle_y = -0.0f;
257 float zoom = -1.8f;
258
259 for (iterations = 1; true; ++iterations) {
260 auto const t1 = std::chrono::high_resolution_clock::now();
261
262 Vec3f eye(5.17831f, 4.56809f, 5.571f);
263 Vec3f target(5.17831f, 4.568091f, 0.0f);
264
265 // camera.pose.translation = position; // (max - min) / 2.0f;
266 float cx = std::cos(angle_x);
267 float cy = std::cos(angle_y);
268 float sx = std::sin(angle_x);
269 float sy = std::sin(angle_y);
270 Vec3f offset = Vec3f(sy * cx, sy * sx, cy) * std::exp(-zoom);
271 // camera.lookAt(position + offset);
272 // camera.lookAt(eye + offset, target);
273 // camera.up = normalize(camera.up + Vec3f(0.0f, 1.0f, 0.0f));
274 auto roll_mat = rotate(Mat4f(), radians(-20.0f), normalize(target - eye));
275 camera.up = Mat3f(roll_mat) * camera.up;
276 std::cout << roll_mat << '\n';
277 std::cout << camera.up << '\n';
278 camera.lookAt(eye, target);
279 // angle_y += 0.01f;
280
281 float max_dist{};
282 map.render(
283 execution::par, camera, image,
284 [&map](auto node, Ray3 ray, float distance) -> bool {
285 // return map.containsOccupied(node);
286 return true;
287 },
288 [&map, &max_dist](auto node, Ray3 ray,
289 float distance) -> std::pair<bool, std::pair<Color, Color>> {
290 float max_distance = 9.07359f;
291
292 if (map.isLeaf(node)) {
293 float d = max_distance;
294 float d2 = max_distance;
295 // if (map.distanceContainsSurface(node)) {
296 auto [a, b] = map.distancePoint<true>(Vec2f(ray.step(distance)));
297 d = map.distanceSomething(b, Vec2f(ray.step(distance)));
298 d2 = a;
299 // } else {
300 // // d = map.distance<true>(Vec2f(ray.step(distance)));
301 // }
302
303 // d = 0.015 > d ? d : max_distance;
304 // d2 = 0.015 > d2 ? d2 : max_distance;
305
306 max_dist = std::max(max_dist, d);
307 Color c = color(d, 0.0, max_distance, 0.7);
308 Color c2 = color(d2, 0.0, max_distance, 0.7);
309
310 // if (0.01 > d) {
311 c2 = map.color(node);
312 // }
313
314 return std::make_pair(true, std::make_pair(c2, c));
315 } else {
316 return std::make_pair(false, std::make_pair(Color{}, Color{}));
317 }
318 },
319 std::make_pair(Color{}, Color{}));
320
321 std::cout << max_dist << '\n';
322
323 auto const t2 = std::chrono::high_resolution_clock::now();
324
325 double row_scale = image.rows() / static_cast<double>(output_rows);
326 double col_scale = image.cols() / static_cast<double>(output_cols);
327
328 auto f = [&](std::size_t i) {
329 for (std::size_t j{}; j < output_cols; ++j) {
330 std::size_t i_scaled = std::floor(i * row_scale);
331 std::size_t j_scaled = std::floor(j * col_scale);
332 img.at<cv::Vec3b>(i, j)[2] = image(i_scaled, j_scaled).first.red;
333 img.at<cv::Vec3b>(i, j)[1] = image(i_scaled, j_scaled).first.green;
334 img.at<cv::Vec3b>(i, j)[0] = image(i_scaled, j_scaled).first.blue;
335 img.at<cv::Vec3b>(i, output_cols + j)[2] = image(i_scaled, j_scaled).second.red;
336 img.at<cv::Vec3b>(i, output_cols + j)[1] = image(i_scaled, j_scaled).second.green;
337 img.at<cv::Vec3b>(i, output_cols + j)[0] = image(i_scaled, j_scaled).second.blue;
338 rgb.at<cv::Vec3b>(i, j)[2] = image(i_scaled, j_scaled).first.red;
339 rgb.at<cv::Vec3b>(i, j)[1] = image(i_scaled, j_scaled).first.green;
340 rgb.at<cv::Vec3b>(i, j)[0] = image(i_scaled, j_scaled).first.blue;
341 mask.at<cv::Vec3b>(i, j)[2] = image(i_scaled, j_scaled).first.empty() ? 0 : 255;
342 mask.at<cv::Vec3b>(i, j)[1] = image(i_scaled, j_scaled).first.empty() ? 0 : 255;
343 mask.at<cv::Vec3b>(i, j)[0] = image(i_scaled, j_scaled).first.empty() ? 0 : 255;
344 }
345 };
346
347#if defined(UFO_TBB)
348 std::for_each(std::execution::par_unseq, output_row_idx.begin(), output_row_idx.end(),
349 f);
350#else
351#if defined(UFO_OMP)
352#pragma omp parallel for
353#endif
354 for (std::size_t i = 0; i < output_rows; ++i) {
355 f(i);
356 }
357#endif
358
359 imwrite("/home/dduberg/ufo/render/topdown.png", rgb);
360 imwrite("/home/dduberg/ufo/render/topdown_mask.png", mask);
361 exit(0);
362
363 auto const t3 = std::chrono::high_resolution_clock::now();
364 std::chrono::duration<double, std::milli> const ufo_ms = t2 - t1;
365 std::chrono::duration<double, std::milli> const interpolate_ms = t3 - t2;
366
367 ufo_total_ms += ufo_ms.count();
368 interpolate_total_ms += interpolate_ms.count();
369
370 std::chrono::duration<double, std::milli> const total_ms = t3 - t1;
371
372 std::cout << std::setw(28) << std::left
373 << "UFO took: " << (ufo_total_ms / iterations) << " ms\n";
374 std::cout << std::setw(28) << std::left
375 << "Interpolate took: " << (interpolate_total_ms / iterations) << " ms\n";
376 std::cout << std::setw(28) << std::left << "Total: "
377 << ((ufo_total_ms + interpolate_total_ms) / iterations) << " ms\n";
378
379 cv::imshow("UFOMap Rendered View", img);
380 std::cout << "Wait "
381 << std::max(1, static_cast<int>(1000 * (1.0 / fps) - total_ms.count()))
382 << " ms\n";
383 // Wait for a keystroke in the window
384 int k =
385 cv::waitKey(std::max(1, static_cast<int>(1000 * (1.0 / fps) - total_ms.count())));
386
387 // cv::waitKey();
388 }
389
390 return 0;
391}
Image class for storing and manipulating 2D pixel data.
Definition image.hpp:78
constexpr T radians(T deg) noexcept
Converts degrees to radians.
Definition math.hpp:86
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326
constexpr T a(Lab< T, Flags > color) noexcept
Returns the un-weighted green–red axis value.
Definition lab.hpp:310
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > max(Geometry const &g)
Returns the maximum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
Definition fun.hpp:72
constexpr Quat< T > normalize(Quat< T > const &q) noexcept
Returns a unit quaternion in the same direction as q.
Definition quat.hpp:679
Mat< 4, 4, T > rotate(Mat< 4, 4, T > const &m, T angle, Vec< 3, T > const &v)
Applies an axis-angle rotation to a 4×4 matrix.
Definition mat.hpp:1535
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > min(Geometry const &g)
Returns the minimum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
Definition fun.hpp:58
constexpr auto distance(A const &a, B const &b)
Computes the minimum distance between two shapes.
Definition distance.hpp:61
Ray in Dim-dimensional space.
Definition ray.hpp:66
Triangle in Dim-dimensional space.
Definition triangle.hpp:70
static constexpr std::size_t size() noexcept
Returns the number of dimensions.
Definition vec.hpp:200