ptcloud: cv::viz3d OpenGL point-cloud/mesh visualization

This commit is contained in:
kirtijindal14
2026-07-09 18:14:01 +05:30
parent 53d308c2a5
commit 3bc72d4efc
11 changed files with 21083 additions and 5 deletions

View File

@@ -1,10 +1,7 @@
set(the_description "High level point cloud and mesh operations")
set(debug_modules "")
if(DEBUG_opencv_ptcloud)
list(APPEND debug_modules opencv_highgui)
endif()
ocv_define_module(ptcloud opencv_geometry opencv_imgproc opencv_features opencv_video ${debug_modules}
# viz3d visualization lives here and imports the window + OpenGL context from highgui.
ocv_define_module(ptcloud opencv_geometry opencv_imgproc opencv_features opencv_video opencv_flann opencv_highgui
WRAP java objc python js
)
ocv_target_link_libraries(${the_module} ${LAPACK_LIBRARIES})

View File

@@ -12,6 +12,7 @@
#include "opencv2/ptcloud/odometry_frame.hpp"
#include "opencv2/ptcloud/odometry_settings.hpp"
#include "opencv2/ptcloud/slam.hpp"
#include "opencv2/ptcloud/viz3d.hpp"
/**
@defgroup ptcloud Point Cloud Processing

View File

@@ -0,0 +1,188 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_PTCLOUD_VIZ3D_HPP
#define OPENCV_PTCLOUD_VIZ3D_HPP
#include "opencv2/core.hpp"
namespace cv { namespace viz3d {
//! Render modes for cv::viz3d::showBox / cv::viz3d::showPlane / cv::viz3d::showSphere
enum RenderMode
{
RENDER_SIMPLE = 0,
RENDER_SHADING = 1,
RENDER_WIREFRAME = 2,
};
/** @brief Sets the view's perspective on a viz3d window.
@param win_name Name of the viz3d window.
@param fov Vertical field of view in radians.
@param z_near Minimum clip distance.
@param z_far Maximum clip distance.
*/
CV_EXPORTS_W void setPerspective(const String& win_name, float fov, float z_near, float z_far);
/** @brief Hides or shows the grid on a viz3d window.
@param win_name Name of the viz3d window.
@param visible Should the grid be shown?
*/
CV_EXPORTS_W void setGridVisible(const String& win_name, bool visible);
/** @brief Sets the properties of the light used on a viz3d window.
@param win_name Name of the viz3d window.
@param direction Direction any point to the sun.
@param ambient Ambient light color.
@param diffuse Diffuse light color.
*/
CV_EXPORTS_W void setSun(const String& win_name, const Vec3f& direction, const Vec3f& ambient, const Vec3f& diffuse);
/** @brief Sets the properties of the sky used on a viz3d window.
@param win_name Name of the viz3d window.
@param color Sky color.
*/
CV_EXPORTS_W void setSky(const String& win_name, const Vec3f& color);
/** @brief Shows a box object in the specified viz3d window. See cv::viz3d::destroyObject.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param size Box size.
@param color Box color.
@param mode Render mode.
*/
CV_EXPORTS_W void showBox(const String& win_name, const String& obj_name, const Vec3f& size, const Vec3f& color, RenderMode mode = RENDER_SIMPLE);
/** @brief Shows a plane object in the specified viz3d window. See cv::viz3d::destroyObject.
The place faces the positive Y axis by default.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param size Plane size.
@param color Plane color.
@param mode Render mode.
*/
CV_EXPORTS_W void showPlane(const String& win_name, const String& obj_name, const Vec2f& size, const Vec3f& color, RenderMode mode = RENDER_SIMPLE);
/** @brief Shows a sphere object in the specified viz3d window. See cv::viz3d::destroyObject.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param radius Sphere radius.
@param color Sphere color.
@param mode Render mode.
@param divs The higher this integer is the more detail (triangles) the sphere has.
*/
CV_EXPORTS_W void showSphere(const String& win_name, const String& obj_name, float radius, const Vec3f& color, RenderMode mode = RENDER_SIMPLE, int divs = 3);
/** @brief Shows a camera trajectory object in the specified viz3d window. See cv::viz3d::destroyObject.
The camera trajectory data array must be 2D. Each row has a width of 6, where the first
3 components are the position and the second 3 components are the direction of the camera.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param trajectory Camera trajectory data.
@param aspect Aspect ratio of the camera frustum.
@param scale Scale applied to camera frustums.
@param frustum_color Color of the frustums.
@param line_color Color of the line.
*/
// Not CV_EXPORTS_W: the auto-bindings generator mishandles the two trailing
// Vec3f defaults (like the other Vec3f-taking viz3d functions, it stays C++-only).
CV_EXPORTS void showCameraTrajectory(
const String& win_name, const String& obj_name, InputArray trajectory,
float aspect, float scale, Vec3f frustum_color = Vec3f(1.0f, 1.0f, 1.0f),
Vec3f line_color = Vec3f(0.5f, 0.5f, 0.5f));
/** @brief Shows a mesh object in the specified viz3d window. See cv::viz3d::destroyObject.
The vertices array must be 2D. If shading is disabled (the default option), each row has a width of
3 (xyz), 6 (xyz, rgb) or 9 (xyz, rgb, uvw) where uvw is the normal, so that each row represents a vertex.
Shading is only enabled when using normals.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param verts Vertices input array.
@param indices Indices input array.
*/
CV_EXPORTS void showMesh(const String& win_name, const String& obj_name, InputArray verts, InputArray indices);
/** @overload Shows a mesh object in the specified viz3d window. See cv::viz3d::destroyObject.
The vertices array must be 2D, where each row has a width of 3 (xyz), 6 (xyz, rgb) or 9 (xyz, rgb, uvw)
where uvw is the normal, so that each row represents a vertex. Shading is only enabled when using normals.
Points are grouped in triplets to make triangles (points 1, 2 and 3, points 4, 5 and 6, etc).
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param verts Vertices input array.
@param indices Indices input array.
*/
CV_EXPORTS_AS(showMesh2) void showMesh(const String& win_name, const String& obj_name, InputArray verts);
/** @brief Shows a point cloud object in the specified viz3d window. See cv::viz3d::destroyObject.
The points array must be 2D, where each row has either a width of 6 (xyz, rgb), so that
each row represents a point.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param points Vertices input array.
*/
CV_EXPORTS_W void showPoints(const String& win_name, const String& obj_name, InputArray points);
/** @brief Shows a colored depth map as a point cloud in the specified viz3d window. See cv::viz3d::destroyObject.
The colored depth map must be a 2D image with 4 channels (RGBD). The points are created assuming
that positive depth means positive position in the Z axis.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param img Input colored depth map.
@param intrinsics Camera intrinsics matrix.
@param scale Scale applied to the coordinates of the points.
*/
CV_EXPORTS_W void showRGBD(const String& win_name, const String& obj_name, InputArray img, const Matx33f& intrinsics, float scale = 1.0f);
/** @brief Shows a lines object in the specified viz3d window. See cv::viz3d::destroyObject.
The points array must be 2D, where each row has either a width of 6 (xyz, rgb), so that
each row represents a point. Points are grouped in pairs to make lines (points 1 and 2,
points 3 and 4, etc).
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param points Vertices input array.
*/
CV_EXPORTS_W void showLines(const String& win_name, const String& obj_name, InputArray points);
/** @brief Sets an object's position in the specified viz3d window.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param position New position.
*/
CV_EXPORTS_W void setObjectPosition(const String& win_name, const String& obj_name, const Vec3f& position);
/** @brief Sets an object's rotation in the specified viz3d window.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
@param rotation New rotation in euler angles (radians).
*/
CV_EXPORTS_W void setObjectRotation(const String& win_name, const String& obj_name, const Vec3f& rotation);
/** @brief Destroys an object created with cv::viz3d::showMesh or cv::viz3d::showPoints.
@param win_name Name of the viz3d window.
@param obj_name Name of the object.
*/
CV_EXPORTS_W void destroyObject(const String& win_name, const String& obj_name);
} // namespace viz3d
} // namespace cv
#endif

View File

@@ -0,0 +1,156 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include <fstream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/ptcloud.hpp> // cv::viz3d now lives in the ptcloud module
using namespace cv;
Mat loadPoints(const String& path)
{
Mat points;
std::ifstream ifs(path);
int _;
float x, y, z, r, g, b;
Vec3f c = Vec3f::all(0.0f);
int count;
std::string str;
std::getline(ifs, str);
for (count = 0; ifs >> _ && ifs >> x && ifs >> z && ifs >> y && ifs >> r && ifs >> g && ifs >> b; ++count)
{
y = -y;
float data[] = { x, y, z, r / 255.0f, g / 255.0f, b / 255.0f };
points.push_back(Mat(Size(6, 1), CV_32F, &data));
c += Vec3f(x, y, z);
}
c /= count;
for (int i = 0; i < count; ++i)
for (int j = 0; j < 3; ++j)
points.at<float>(i, j) -= c(j);
return points;
}
int main()
{
float verts_data[] = {
-0.5, -0.5, 0.0,
-0.5, +0.5, 0.0,
+0.5, +0.5, 0.0,
+0.5, -0.5, 0.0,
};
Mat verts_mat = Mat(Size(3, 4), CV_32F, &verts_data);
int indices_data[] = {
0, 1, 2,
2, 3, 0,
};
Mat indices_mat = Mat(Size(3, 2), CV_32S, &indices_data);
float point_data[] = {
-0.5, -0.5, 0.0, 1.0f, 0.0f, 0.0f,
-0.5, +0.5, 0.0, 0.0f, 1.0f, 0.0f,
+0.5, +0.5, 0.0, 0.0f, 0.0f, 1.0f,
+0.5, -0.5, 0.0, 1.0f, 1.0f, 1.0f,
};
Mat points_mat = Mat(Size(6, 4), CV_32F, &point_data);
float trajectory_data[] = {
-0.0, +5.0, +0.0, -1.0f, -1.0f, -1.0f,
-5.0, +4.0, +2.0, +0.0f, +0.0f, -1.0f,
-10.0, +3.0, +5.0, -0.5f, +0.2f, -0.5f,
};
Mat trajectory_mat = Mat(Size(6, 3), CV_32F, &trajectory_data);
// Images taken from https://rgbd-dataset.cs.washington.edu
// Papers that need to be cited to use this data:
// [1] N. Silberman, D. Hoiem, P. Kohli, R. Fergus. Indoor segmentation and support inference from rgbd images. In ECCV, 2012.
// [2] A.Janoch, S.Karayev, Y.Jia, J.T.Barron, M.Fritz, K.Saenko, and T.Darrell.A category - level 3 - d object dataset : Putting the kinect to work.In ICCV Workshop on Consumer Depth Cameras for Computer Vision, 2011.
// [3] J.Xiao, A.Owens, and A.Torralba.SUN3D : A database of big spaces reconstructed using SfMand object labels.In ICCV, 2013
Mat rgbd_components[] = {
imread(samples::findFile("rgbd-color.jpg"), IMREAD_COLOR),
imread(samples::findFile("rgbd-depth.png"), IMREAD_ANYDEPTH | IMREAD_ANYCOLOR)
};
rgbd_components[0].convertTo(rgbd_components[0], CV_32F);
rgbd_components[1].convertTo(rgbd_components[1], CV_32F);
Mat rgbd;
merge(rgbd_components, 2, rgbd);
cvtColor(rgbd, rgbd, COLOR_BGRA2RGBA);
// Point cloud data taken from https://sketchfab.com/3d-models/anthidium-forcipatum-point-cloud-3493da15a8db4f34929fc38d9d0fcb2c
Mat bee_mat = loadPoints(samples::findFile("anthidium-forcipatum.csv"));
// Show two instances of the same example mesh
viz3d::showMesh("viz3d", "mesh1", verts_mat, indices_mat);
viz3d::showMesh("viz3d", "mesh2", verts_mat, indices_mat);
viz3d::setObjectPosition("viz3d", "mesh1", { -2.0f, 0.0f, 0.0f });
viz3d::setObjectPosition("viz3d", "mesh2", { 2.0f, 0.0f, 0.0f });
// Show an example point cloud
viz3d::showPoints("viz3d", "points", points_mat);
// Show a bee point cloud
viz3d::showPoints("viz3d", "bee", bee_mat);
viz3d::setObjectPosition("viz3d", "bee", { 0.0f, 0.0f, 5.0f });
// Show RGBD image as points
viz3d::showRGBD("rgbd", "rgbd", rgbd, {
529.5f, 0.0f, 365.0f,
0.0f, 529.5f, 265.0f,
0.0f, 0.0f, 1.0f
}, 0.1f);
viz3d::setObjectPosition("rgbd", "rgbd", { 0.0f, 0.0f, 0.0f });
viz3d::setGridVisible("rgbd", true);
// Show a solid box
viz3d::showBox("viz3d", "box1", { 0.25f, 0.25f, 0.25f }, { 0.5f, 1.0f, 0.5f });
viz3d::setObjectPosition("viz3d", "box1", { -5.0f, 0.0f, -5.0f });
// Show 3 wireframe boxes
viz3d::showBox("viz3d", "box2", { 1.0f, 0.5f, 0.5f }, { 1.0f, 0.5f, 0.5f }, viz3d::RENDER_SIMPLE);
viz3d::showBox("viz3d", "box3", { 0.5f, 1.0f, 0.5f }, { 0.5f, 1.0f, 0.5f }, viz3d::RENDER_WIREFRAME);
viz3d::showBox("viz3d", "box4", { 0.5f, 0.5f, 1.0f }, { 0.5f, 0.5f, 1.0f}, viz3d::RENDER_SHADING);
viz3d::setObjectPosition("viz3d", "box2", { 5.0f, 0.0f, 5.0f });
viz3d::setObjectPosition("viz3d", "box3", { -5.0f, 0.0f, 5.0f });
viz3d::setObjectPosition("viz3d", "box4", { -5.0f, 0.0f, 0.0f });
// Show a solid sphere
viz3d::showSphere("viz3d", "sphere1", 1.0f, { 0.7f, 0.9f, 0.7f }, viz3d::RENDER_SHADING);
viz3d::setObjectPosition("viz3d", "sphere1", { 0.0f, 0.0f, -5.0f });
// Show wireframe sphere
viz3d::showSphere("viz3d", "sphere2", 1.0f, { 0.7f, 0.9f, 0.7f }, viz3d::RENDER_WIREFRAME);
viz3d::setObjectPosition("viz3d", "sphere2", { 5.0f, 0.0f, 0.0f });
// Show plane
viz3d::showPlane("viz3d", "plane1", { 1.5f, 1.0f }, { 0.8f, 0.5f, 0.3f });
viz3d::setObjectPosition("viz3d", "plane1", { 5.0f, 0.0f, -5.0f });
viz3d::showCameraTrajectory("viz3d", "trajectory", trajectory_mat, 1.5f, 0.2f);
float x = 0.0f;
while (waitKey(16) != 27)
{
// Animate objects
viz3d::setObjectRotation("viz3d", "mesh1", { x, 0.0f, 0.0f });
viz3d::setObjectRotation("viz3d", "mesh2", { 0.0f, 0.0f, x });
x += 0.01f;
}
return 0;
}

View File

@@ -0,0 +1,25 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_PTCLOUD_VIZ3D_GRID_TICKS_HPP
#define OPENCV_PTCLOUD_VIZ3D_GRID_TICKS_HPP
namespace cv { namespace viz3d { namespace detail {
// Grid line spacing, snapped so dist_scale / tick_step stays in [2, 4].
// Pure math (no OpenGL) so it is unit-testable headless. Terminates for any
// finite dist_scale (regression guard for the old logf(1.0)=0 -> inf hang).
inline float gridTickStep(float dist_scale)
{
float tick_step = 1.0f;
while (dist_scale / tick_step > 4.0f)
tick_step *= 2.0f;
while (tick_step > 1e-6f && dist_scale / tick_step < 2.0f)
tick_step *= 0.5f;
return tick_step;
}
}}} // namespace cv::viz3d::detail
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,209 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#ifndef OPENCV_PTCLOUD_VIZ3D_PRIVATE_HPP
#define OPENCV_PTCLOUD_VIZ3D_PRIVATE_HPP
#include "../precomp.hpp"
#include "opencv2/core/private.hpp" // HAVE_OPENGL from cvconfig.h
#include "opencv2/core/opengl.hpp"
#include "opencv2/highgui.hpp" // window + OpenGL context (imported from highgui)
#include "opencv2/ptcloud/viz3d.hpp" // public viz3d API declarations
#include <map>
#ifdef HAVE_OPENGL
namespace cv { namespace viz3d {
// Stores a view's matrices
class View
{
public:
View();
void setAspect(float aspect);
void setPerspective(float fov, float z_near, float z_far);
void rotate(float dx, float dy); // Rotates the camera using mouse input
void move(float dx, float dy); // Moves the camera using mouse input
void scaleDistance(float amount);
inline Vec3f getOrigin() const { return this->origin; }
inline Vec3f getPosition() const { return this->position; }
inline float getDistance() const { return this->distance; }
inline Matx44f getView() const { return this->view; }
inline Matx44f getProj() const { return this->proj; }
private:
void lookAt(const Vec3f& point, const Vec3f& up);
float aspect;
float fov;
float z_near;
float z_far;
Matx44f proj;
Matx44f view;
Vec3f origin;
Vec3f position;
Vec3f up;
float distance;
};
// Stores information about a light
struct Light
{
Vec3f direction;
Vec3f ambient;
Vec3f diffuse;
};
// Base class for viz3d objects which can be rendered
class Object
{
public:
Object();
virtual ~Object() = default;
void setPosition(const Vec3f& position);
void setRotation(const Vec3f& rotation);
virtual void draw(const View& view, const Light& light) = 0;
virtual String getShaderName() = 0;
virtual ogl::Program buildShader() = 0;
virtual void setShader(ogl::Program program) = 0;
inline Matx44f getModel() const { return this->model; }
private:
void updateModel();
Vec3f position;
Vec3f rotation;
Matx44f model;
};
// Class which stores the viz3d data associated to a window.
class Window
{
public:
Window(const String& name);
~Window();
Object* get(const String& obj_name);
void set(const String& obj_name, Object* obj);
void setSun(const Vec3f& direction, const Vec3f& ambient, const Vec3f& diffuse);
void setSky(const Vec3f& color);
void setGridVisible(bool visible);
void draw();
void onMouse(int event, int x, int y, int flags);
inline View& getView() { return this->view; }
private:
String name;
Size size;
Light sun;
Vec3f sky_color;
View view;
int l_mouse_x;
int l_mouse_y;
Object* crosshair;
Object* grid;
std::map<String, Object*> objects;
std::map<String, ogl::Program> shaders;
};
// Class which stores the viz3d data associated to a mesh object.
class Mesh : public Object
{
public:
Mesh(InputArray verts, InputArray indices);
Mesh(InputArray verts);
virtual void draw(const View& view, const Light& light) override;
virtual String getShaderName() override;
virtual ogl::Program buildShader() override;
virtual void setShader(ogl::Program program) override;
private:
void initVA(int width);
ogl::Program program;
ogl::VertexArray va;
ogl::Buffer verts;
ogl::Buffer indices;
int index_type;
int model_loc;
int view_loc;
int proj_loc;
int sun_direction_loc;
int sun_ambient_loc;
int sun_diffuse_loc;
};
// Class which stores the viz3d data associated to a lines object.
class Lines : public Object
{
public:
Lines(InputArray points, int count = -1);
virtual void draw(const View& view, const Light& light) override;
void update(InputArray points);
virtual String getShaderName() override;
virtual ogl::Program buildShader() override;
virtual void setShader(ogl::Program program) override;
private:
ogl::Program program;
ogl::VertexArray va;
ogl::Buffer points;
int model_loc;
int view_loc;
int proj_loc;
int count;
};
// Data necessary for drawing a point cloud on a window.
class PointCloud : public Object
{
public:
PointCloud(InputArray points);
virtual void draw(const View& view, const Light& light) override;
virtual String getShaderName() override;
virtual ogl::Program buildShader() override;
virtual void setShader(ogl::Program program) override;
private:
ogl::Program program;
ogl::VertexArray va;
ogl::Buffer points;
int model_loc;
int view_loc;
int proj_loc;
};
}} // namespace cv::viz3d
#endif // HAVE_OPENGL
#endif

View File

@@ -0,0 +1,82 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
#include "test_precomp.hpp"
#include <opencv2/highgui.hpp> // updateWindow / destroyWindow
#include "../src/viz3d/grid_ticks.hpp" // GL-free grid spacing helper
namespace opencv_test { namespace {
using namespace cv;
// Regression for the grid tick_step infinite-loop hang (#1): the old code did
// logf(1.0) == 0 -> division -> inf -> the halving loop never terminated for
// distance*scale > 4. gridTickStep must terminate and stay finite/positive for
// every distance, including the region that used to hang. GL-free (runs in CI).
TEST(Viz3D, grid_tick_step)
{
// Values span below/at/above the old hang threshold (dist_scale > 4).
const float samples[] = { 0.03f, 0.9f, 3.0f, 4.0f, 5.0f, 13.4f, 40.0f, 400.0f, 4000.0f };
for (float ds : samples)
{
float ts = viz3d::detail::gridTickStep(ds);
ASSERT_TRUE(std::isfinite(ts)) << "ds=" << ds;
ASSERT_GT(ts, 0.0f) << "ds=" << ds;
float ratio = ds / ts;
EXPECT_GE(ratio, 2.0f - 1e-3f) << "ds=" << ds << " ratio=" << ratio;
EXPECT_LE(ratio, 4.0f + 1e-3f) << "ds=" << ds << " ratio=" << ratio;
}
}
// viz3d is OpenGL/window based. Skip when no GL context can be created
// (e.g. headless CI without a display).
static bool viz3dAvailable()
{
try
{
viz3d::showPoints("viz3d_gl_probe", "p", Mat::zeros(4, 6, CV_32F));
destroyWindow("viz3d_gl_probe");
return true;
}
catch (const cv::Exception&)
{
return false;
}
}
// Smoke test for the public viz3d API. Builds a scene and forces redraws; passes
// if nothing throws. Exercises the paths touched by review fixes: #3 (showRGBD),
// #4 (degenerate up-vector trajectory), and the grid render path. The #1 hang
// itself is distance-triggered (no public camera-distance setter) and is covered
// by the GL-free Viz3D.grid_tick_step test above.
TEST(Viz3D, render_scene_smoke)
{
if (!viz3dAvailable())
throw cvtest::SkipTestException("viz3d/OpenGL not available (no GL context)");
const String w = "viz3d_test";
Mat pts(256, 6, CV_32F);
randu(pts, 0.0f, 1.0f);
EXPECT_NO_THROW(viz3d::showPoints(w, "pts", pts));
EXPECT_NO_THROW(viz3d::setGridVisible(w, true));
EXPECT_NO_THROW(viz3d::showBox(w, "box", Vec3f::all(1.0f), Vec3f(1, 0, 0)));
EXPECT_NO_THROW(viz3d::showSphere(w, "sphere", 1.0f, Vec3f(0, 1, 0)));
// forward = (0,+1,0) and (0,-1,0): the degenerate up-vector case guarded by #4.
float traj[] = { 0,0,0, 0,1,0, 1,0,0, 0,-1,0 };
EXPECT_NO_THROW(viz3d::showCameraTrajectory(w, "traj", Mat(2, 6, CV_32F, traj), 1.0f, 0.5f));
Mat rgbd(16, 16, CV_32FC4, Scalar(120, 120, 120, 500)); // #3 showRGBD path
EXPECT_NO_THROW(viz3d::showRGBD(w, "rgbd", rgbd, Matx33f(8, 0, 8, 0, 8, 8, 0, 0, 1), 0.1f));
for (int i = 0; i < 4; ++i)
EXPECT_NO_THROW(updateWindow(w));
EXPECT_NO_THROW(viz3d::destroyObject(w, "pts"));
destroyAllWindows();
}
}} // namespace