Skip to content

Commit e9c155a

Browse files
committed
Camera coordinate frame visualization with LineSet
1 parent 69786b6 commit e9c155a

File tree

4 files changed

+150
-0
lines changed

4 files changed

+150
-0
lines changed

cpp/open3d/geometry/LineSetFactory.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,25 @@ std::shared_ptr<LineSet> LineSet::CreateCameraVisualization(
170170
lines->lines_.push_back({4, 1});
171171
lines->PaintUniformColor({0.0f, 0.0f, 1.0f});
172172

173+
// Add XYZ axes
174+
lines->points_.push_back(
175+
mult(m, Eigen::Vector3d{intrinsic(0, 0) * scale, 0.0, 0.0}));
176+
lines->points_.push_back(
177+
mult(m, Eigen::Vector3d{0.0, intrinsic(1, 1) * scale, 0.0}));
178+
lines->points_.push_back(
179+
mult(m, Eigen::Vector3d{intrinsic(0, 2) * scale,
180+
intrinsic(1, 2) * scale, scale}));
181+
182+
// Add lines for the axes
183+
lines->lines_.push_back({0, 5}); // X axis (red)
184+
lines->lines_.push_back({0, 6}); // Y axis (green)
185+
lines->lines_.push_back({0, 7}); // Z axis (blue)
186+
187+
// Set colors for the axes
188+
lines->colors_.push_back({1.0f, 0.0f, 0.0f}); // Red
189+
lines->colors_.push_back({0.0f, 1.0f, 0.0f}); // Green
190+
lines->colors_.push_back({0.0f, 0.0f, 1.0f}); // Blue
191+
173192
return lines;
174193
}
175194

cpp/open3d/t/geometry/LineSet.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <string>
1111

12+
#include "open3d/core/Dtype.h"
1213
#include "open3d/core/EigenConverter.h"
1314
#include "open3d/core/ShapeUtil.h"
1415
#include "open3d/core/Tensor.h"
@@ -211,6 +212,82 @@ OrientedBoundingBox LineSet::GetOrientedBoundingBox() const {
211212
return OrientedBoundingBox::CreateFromPoints(GetPointPositions());
212213
}
213214

215+
LineSet &LineSet::PaintUniformColor(const core::Tensor &color) {
216+
core::AssertTensorShape(color, {3});
217+
core::Tensor clipped_color = color.To(GetDevice());
218+
if (color.GetDtype() == core::Float32 ||
219+
color.GetDtype() == core::Float64) {
220+
clipped_color = clipped_color.Clip(0.0f, 1.0f);
221+
}
222+
core::Tensor ls_colors =
223+
core::Tensor::Empty({GetLineIndices().GetLength(), 3},
224+
clipped_color.GetDtype(), GetDevice());
225+
ls_colors.AsRvalue() = clipped_color;
226+
SetLineColors(ls_colors);
227+
228+
return *this;
229+
}
230+
231+
LineSet LineSet::CreateCameraVisualization(int view_width_px,
232+
int view_height_px,
233+
const core::Tensor &intrinsic_in,
234+
const core::Tensor &extrinsic_in,
235+
double scale,
236+
const core::Tensor &color) {
237+
core::AssertTensorShape(intrinsic_in, {3, 3});
238+
core::AssertTensorShape(extrinsic_in, {4, 4});
239+
core::Tensor intrinsic = intrinsic_in.To(core::Float32, "CPU:0");
240+
core::Tensor extrinsic = extrinsic_in.To(core::Float32, "CPU:0");
241+
242+
// Calculate points for camera visualization
243+
float w(view_width_px), h(view_height_px), s(scale);
244+
float fx = intrinsic[0][0].Item<float>(),
245+
fy = intrinsic[1][1].Item<float>(),
246+
cx = intrinsic[0][2].Item<float>(),
247+
cy = intrinsic[1][2].Item<float>();
248+
core::Tensor points = core::Tensor::Init<float>({{0.f, 0.f, 0.f}, // origin
249+
{0.f, 0.f, s},
250+
{w * s, 0.f, s},
251+
{w * s, h * s, s},
252+
{0.f, h * s, s},
253+
// Add XYZ axes
254+
{fx * s, 0.f, 0.f},
255+
{0.f, fy * s, 0.f},
256+
{cx * s, cy * s, s}});
257+
points = (intrinsic.Inverse().Matmul(points.T()) -
258+
extrinsic.Slice(0, 0, 3).Slice(1, 3, 4))
259+
.T()
260+
.Matmul(extrinsic.Slice(0, 0, 3).Slice(1, 0, 3));
261+
262+
// Add lines for camera frame and XYZ axes
263+
core::Tensor lines = core::Tensor::Init<int>({{0, 1},
264+
{0, 2},
265+
{0, 3},
266+
{0, 4},
267+
{1, 2},
268+
{2, 3},
269+
{3, 4},
270+
{4, 1},
271+
// Add XYZ axes
272+
{0, 5},
273+
{0, 6},
274+
{0, 7}});
275+
276+
// Convert Eigen data to Tensors
277+
LineSet lineset(points, lines);
278+
if (color.NumElements() == 3) {
279+
lineset.PaintUniformColor(color);
280+
} else {
281+
lineset.PaintUniformColor(core::Tensor::Init<float>({0.f, 0.f, 1.f}));
282+
}
283+
auto &lscolors = lineset.GetLineColors();
284+
lscolors[8] = core::Tensor::Init<float>({1.f, 0.f, 0.f}); // Red
285+
lscolors[9] = core::Tensor::Init<float>({0.f, 1.f, 0.f}); // Green
286+
lscolors[10] = core::Tensor::Init<float>({0.f, 0.f, 1.f}); // Blue
287+
288+
return lineset;
289+
}
290+
214291
} // namespace geometry
215292
} // namespace t
216293
} // namespace open3d

cpp/open3d/t/geometry/LineSet.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,12 @@ class LineSet : public Geometry, public DrawableGeometry {
337337
/// \return Rotated line set.
338338
LineSet &Rotate(const core::Tensor &R, const core::Tensor &center);
339339

340+
/// \brief Assigns uniform color to all lines of the LineSet.
341+
///
342+
/// \param color RGB color for the LineSet. {3,} shaped Tensor.
343+
/// Floating color values are clipped between 0.0 and 1.0.
344+
LineSet &PaintUniformColor(const core::Tensor &color);
345+
340346
/// \brief Returns the device attribute of this LineSet.
341347
core::Device GetDevice() const override { return device_; }
342348

@@ -385,6 +391,23 @@ class LineSet : public Geometry, public DrawableGeometry {
385391
double scale = 1.0,
386392
bool capping = true) const;
387393

394+
/// Factory function to create a LineSet from intrinsic and extrinsic
395+
/// matrices.
396+
///
397+
/// \param view_width_px The width of the view, in pixels.
398+
/// \param view_height_px The height of the view, in pixels.
399+
/// \param intrinsic The intrinsic matrix {3,3} shape.
400+
/// \param extrinsic The extrinsic matrix {4,4} shape.
401+
/// \param scale camera scale
402+
/// \param color tensor with float32 dtype and shape {3}. Default is blue.
403+
static LineSet CreateCameraVisualization(int view_width_px,
404+
int view_height_px,
405+
const core::Tensor &intrinsic,
406+
const core::Tensor &extrinsic,
407+
double scale,
408+
const core::Tensor &color = {}
409+
);
410+
388411
protected:
389412
core::Device device_ = core::Device("CPU:0");
390413
TensorMap point_attr_;

cpp/pybind/t/geometry/lineset.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,37 @@ transformation as :math:`P = R(P) + t`)");
299299
mesh = lines.extrude_linear([0,1,0])
300300
o3d.visualization.draw([{'name': 'L', 'geometry': mesh}])
301301
302+
)");
303+
line_set.def("paint_uniform_color", &LineSet::PaintUniformColor, "color"_a,
304+
"Assigns unifom color to all the lines of the LineSet. "
305+
"Floating color values are clipped between 00 and 1.0. Input "
306+
"`color` should be a (3,) shape tensor.");
307+
line_set.def_static(
308+
"create_camera_visualization", &LineSet::CreateCameraVisualization,
309+
"view_width_px"_a, "view_height_px"_a, "intrinsic"_a, "extrinsic"_a,
310+
"scale"_a = 1.f, "color"_a = core::Tensor({}, core::Float32),
311+
R"(Factory function to create a LineSet from intrinsic and extrinsic
312+
matrices. Camera reference frame is shown with XYZ axes in RGB.
313+
314+
Args:
315+
view_width_px (int): The width of the view, in pixels.
316+
view_height_px (int): The height of the view, in pixels.
317+
intrinsic (open3d.core.Tensor): The intrinsic matrix {3,3} shape.
318+
extrinsic (open3d.core.Tensor): The extrinsic matrix {4,4} shape.
319+
scale (float): camera scale
320+
color (open3d.core.Tensor): color with float32 and shape {3}. Default is blue.
321+
322+
Example:
323+
324+
Draw a purple camera frame with XYZ axes in RGB.
325+
326+
import open3d.core as o3c
327+
from open3d.t.geometry import LineSet
328+
from open3d.visualization import draw
329+
K = o3c.Tensor([[512, 0, 512], [0, 512, 512], [0, 0, 1]], dtype=o3c.float32)
330+
T = o3c.Tensor.eye(4, dtype=o3c.float32)
331+
ls = LineSet.create_camera_visualization(1024, 1024, K, T, 1, [0.8, 0.2, 0.8])
332+
draw([ls])
302333
)");
303334
}
304335

0 commit comments

Comments
 (0)