Visualization Tutorial
Introduction
이 튜토리얼에서는 Zivid SDK 및 타사 라이브러리를 사용하여 Zivid 카메라로 캡처한 3D 및 2D 데이터를 시각화하는 방법을 설명합니다.
Prerequisites
Zivid Software 를 설치합니다.
Python의 경우: install zivid-python
이 튜토리얼은 Zivid Frame으로 시작합니다. Capture Tutorial 을 보면 프레임 캡처 방법에 대한 자세한 내용을 확인할 수 있습니다.
Point Cloud
Zivid SDK in C++ and C#
프레임이 있으면 포인트 클라우드를 시각화할 수 있습니다.
std::cout << "Setting up visualization" << std::endl;
Zivid::Visualization::Visualizer visualizer;
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
Console.WriteLine("Setting up visualization");
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
Console.WriteLine("Visualizing point cloud");
visualizer.Show(frame);
visualizer.ShowMaximized();
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizer.Run();
}
포인트 클라우드 객체에서도 포인트 클라우드를 시각화할 수 있습니다.
std::cout << "Getting point cloud from frame" << std::endl;
auto pointCloud = frame.pointCloud();
std::cout << "Setting up visualization" << std::endl;
Zivid::Visualization::Visualizer visualizer;
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(pointCloud);
visualizer.resetToFit();
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
Console.WriteLine("Getting point cloud from frame");
var pointCloud = frame.PointCloud;
Console.WriteLine("Setting up visualization");
var visualizer = new Zivid.NET.Visualization.Visualizer();
Console.WriteLine("Visualizing point cloud");
visualizer.Show(pointCloud);
visualizer.ShowMaximized();
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizer.Run();
Live 3D Point Cloud
The Zivid SDK can be used to continuously capture and visualize 3D point clouds in a loop.
Zivid SDK in C++
The visualizer runs in the main thread while a dedicated thread continuously captures new frames and pushes them to the visualizer. The visualizer must be created and run in the same thread, so keeping it in the main thread lets it outlive the capture thread.
std::cout << "Setting up visualization" << std::endl;
auto visualizer = Zivid::Visualization::Visualizer();
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::atomic_bool visualizerRunning{ true };
std::exception_ptr captureException;
std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() {
try
{
while(visualizerRunning)
{
const auto newFrame = camera.capture2D3D(settings);
if(visualizerRunning)
{
visualizer.show(newFrame);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
catch(...)
{
captureException = std::current_exception();
visualizer.close();
}
});
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
visualizerRunning = false;
captureThread.join();
if(captureException)
{
std::rethrow_exception(captureException);
}
std::cout << "Visualizer closed" << std::endl;
Console.WriteLine("Setting up visualization");
var visualizerRunning = new ManualResetEventSlim(false);
Zivid.NET.Visualization.Visualizer visualizerHandle = null;
var visualizerReady = new ManualResetEventSlim(false);
var visualizationThread = new Thread(() =>
{
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
// Pass the visualizer to the main thread
visualizerHandle = visualizer;
visualizerReady.Set();
Console.WriteLine("Visualizing point cloud");
visualizer.ShowMaximized();
visualizer.Show(frame);
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizerRunning.Set();
visualizer.Run();
visualizerRunning.Reset();
}
});
visualizationThread.Start();
// Get the visualizer handle in the main thread
visualizerReady.Wait();
visualizerRunning.Wait();
while (visualizerRunning.IsSet)
{
frame = camera.Capture2D3D(settings);
if (!visualizerRunning.IsSet)
break;
visualizerHandle.Show(frame);
Thread.Sleep(10);
}
visualizationThread.Join();
Console.WriteLine("Visualizer closed");
print("Setting up visualization")
visualizer_running = threading.Event()
print("Visualizing point cloud")
with zivid.visualization.Visualizer() as visualizer:
visualizer.show(frame)
visualizer.reset_to_fit()
def _capture_thread() -> None:
while visualizer_running.is_set():
new_frame = camera.capture_2d_3d(settings)
if visualizer_running.is_set():
visualizer.show(new_frame)
time.sleep(0.01)
capture_thread = threading.Thread(target=_capture_thread)
print("Running visualizer. Blocking until window closes.")
visualizer_running.set()
capture_thread.start()
visualizer.run()
visualizer_running.clear()
capture_thread.join()
print("Visualizer closed")
To exit the loop by pressing ‘q’ in the terminal:
std::cout << "Setting up visualization" << std::endl;
auto visualizer = Zivid::Visualization::Visualizer();
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::atomic_bool visualizerRunning{ true };
std::exception_ptr captureException;
std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() {
try
{
std::cout << "Press 'q' in the terminal to quit " << std::endl;
while(visualizerRunning)
{
if(getKeyNonBlocking() == 'q')
{
std::cout << "Closing application because user pressed 'q'" << std::endl;
visualizer.close();
break;
}
const auto newFrame = camera.capture2D3D(settings);
if(visualizerRunning)
{
visualizer.show(newFrame);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
catch(...)
{
captureException = std::current_exception();
visualizer.close();
}
});
std::cout << "Running visualizer. Blocking until the window closes or 'q' is pressed." << std::endl;
visualizer.run();
visualizerRunning = false;
captureThread.join();
if(captureException)
{
std::rethrow_exception(captureException);
}
std::cout << "Visualizer closed" << std::endl;
Console.WriteLine("Setting up visualization");
var visualizerRunning = new ManualResetEventSlim(false);
var acceptEnd = new ManualResetEventSlim(true);
var quitRequested = new ManualResetEventSlim(false);
Zivid.NET.Visualization.Visualizer visualizerHandle = null;
var visualizerReady = new ManualResetEventSlim(false);
var visualizationThread = new Thread(() =>
{
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
// Pass the visualizer to the main thread
visualizerHandle = visualizer;
visualizerReady.Set();
Console.WriteLine("Visualizing point cloud");
visualizer.ShowMaximized();
visualizer.Show(frame);
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
do
{
visualizerRunning.Set();
visualizer.Run();
visualizerRunning.Reset();
if (quitRequested.IsSet)
break;
Console.WriteLine(
"Visualizer window closed by user. It will be reopened if we're currently capturing."
);
} while (!acceptEnd.IsSet);
}
});
visualizationThread.Start();
// Get the visualizer handle in the main thread
visualizerReady.Wait();
visualizerRunning.Wait();
Console.WriteLine("Press 'q' in the terminal to quit");
while (visualizerRunning.IsSet)
{
if (Console.KeyAvailable)
{
var key = Console.ReadKey(intercept: true);
if (key.KeyChar == 'q')
{
Console.WriteLine("Closing application because user pressed 'q'");
quitRequested.Set();
Application.DoEvents();
foreach (Form form in Application.OpenForms)
{
if (form.Text.Contains("Zivid"))
{
form.Invoke(new Action(() => form.Close()));
break;
}
}
}
}
else
{
acceptEnd.Reset();
frame = camera.Capture2D3D(settings);
visualizerHandle.Show(frame);
acceptEnd.Set();
}
Thread.Sleep(10);
}
visualizationThread.Join();
Console.WriteLine("Visualizer closed");
print("Setting up visualization")
visualizer_running = threading.Event()
visualizer_running.set()
use_raw_terminal = sys.platform != "win32" and sys.stdin.isatty()
if use_raw_terminal:
old_terminal_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
print("Visualizing point cloud")
with zivid.visualization.Visualizer() as visualizer:
visualizer.show(frame)
visualizer.reset_to_fit()
def _capture_and_keypress_thread() -> None:
print("Press 'q' in the terminal to quit")
while visualizer_running.is_set():
if _get_key_non_blocking() == "q":
print("Closing application because user pressed 'q'")
visualizer.close()
break
new_frame = camera.capture_2d_3d(settings)
if visualizer_running.is_set():
visualizer.show(new_frame)
time.sleep(0.01)
capture_thread = threading.Thread(target=_capture_and_keypress_thread)
capture_thread.start()
print("Running visualizer. Blocking until the window closes or 'q' is pressed.")
visualizer.run()
visualizer_running.clear()
capture_thread.join()
print("Visualizer closed")
finally:
if use_raw_terminal:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_terminal_settings)
Live 3D Point Cloud
The Zivid SDK can be used to continuously capture and visualize 3D point clouds in a loop.
Zivid SDK in C++
The visualizer runs in a dedicated thread while the main thread continuously captures new frames and pushes them to the visualizer.
std::cout << "Setting up visualization" << std::endl;
auto visualizer = Zivid::Visualization::Visualizer();
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::atomic_bool visualizerRunning{ true };
std::exception_ptr captureException;
std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() {
try
{
while(visualizerRunning)
{
const auto newFrame = camera.capture2D3D(settings);
if(visualizerRunning)
{
visualizer.show(newFrame);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
catch(...)
{
captureException = std::current_exception();
visualizer.close();
}
});
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
visualizerRunning = false;
captureThread.join();
if(captureException)
{
std::rethrow_exception(captureException);
}
std::cout << "Visualizer closed" << std::endl;
Console.WriteLine("Setting up visualization");
var visualizerRunning = new ManualResetEventSlim(false);
Zivid.NET.Visualization.Visualizer visualizerHandle = null;
var visualizerReady = new ManualResetEventSlim(false);
var visualizationThread = new Thread(() =>
{
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
// Pass the visualizer to the main thread
visualizerHandle = visualizer;
visualizerReady.Set();
Console.WriteLine("Visualizing point cloud");
visualizer.ShowMaximized();
visualizer.Show(frame);
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizerRunning.Set();
visualizer.Run();
visualizerRunning.Reset();
}
});
visualizationThread.Start();
// Get the visualizer handle in the main thread
visualizerReady.Wait();
visualizerRunning.Wait();
while (visualizerRunning.IsSet)
{
frame = camera.Capture2D3D(settings);
if (!visualizerRunning.IsSet)
break;
visualizerHandle.Show(frame);
Thread.Sleep(10);
}
visualizationThread.Join();
Console.WriteLine("Visualizer closed");
print("Setting up visualization")
visualizer_running = threading.Event()
print("Visualizing point cloud")
with zivid.visualization.Visualizer() as visualizer:
visualizer.show(frame)
visualizer.reset_to_fit()
def _capture_thread() -> None:
while visualizer_running.is_set():
new_frame = camera.capture_2d_3d(settings)
if visualizer_running.is_set():
visualizer.show(new_frame)
time.sleep(0.01)
capture_thread = threading.Thread(target=_capture_thread)
print("Running visualizer. Blocking until window closes.")
visualizer_running.set()
capture_thread.start()
visualizer.run()
visualizer_running.clear()
capture_thread.join()
print("Visualizer closed")
To exit the loop by pressing ‘q’ in the terminal:
std::cout << "Setting up visualization" << std::endl;
auto visualizer = Zivid::Visualization::Visualizer();
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::atomic_bool visualizerRunning{ true };
std::exception_ptr captureException;
std::thread captureThread([&camera, &settings, &visualizer, &visualizerRunning, &captureException]() {
try
{
std::cout << "Press 'q' in the terminal to quit " << std::endl;
while(visualizerRunning)
{
if(getKeyNonBlocking() == 'q')
{
std::cout << "Closing application because user pressed 'q'" << std::endl;
visualizer.close();
break;
}
const auto newFrame = camera.capture2D3D(settings);
if(visualizerRunning)
{
visualizer.show(newFrame);
}
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
catch(...)
{
captureException = std::current_exception();
visualizer.close();
}
});
std::cout << "Running visualizer. Blocking until the window closes or 'q' is pressed." << std::endl;
visualizer.run();
visualizerRunning = false;
captureThread.join();
if(captureException)
{
std::rethrow_exception(captureException);
}
std::cout << "Visualizer closed" << std::endl;
Console.WriteLine("Setting up visualization");
var visualizerRunning = new ManualResetEventSlim(false);
var acceptEnd = new ManualResetEventSlim(true);
var quitRequested = new ManualResetEventSlim(false);
Zivid.NET.Visualization.Visualizer visualizerHandle = null;
var visualizerReady = new ManualResetEventSlim(false);
var visualizationThread = new Thread(() =>
{
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
// Pass the visualizer to the main thread
visualizerHandle = visualizer;
visualizerReady.Set();
Console.WriteLine("Visualizing point cloud");
visualizer.ShowMaximized();
visualizer.Show(frame);
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
do
{
visualizerRunning.Set();
visualizer.Run();
visualizerRunning.Reset();
if (quitRequested.IsSet)
break;
Console.WriteLine(
"Visualizer window closed by user. It will be reopened if we're currently capturing."
);
} while (!acceptEnd.IsSet);
}
});
visualizationThread.Start();
// Get the visualizer handle in the main thread
visualizerReady.Wait();
visualizerRunning.Wait();
Console.WriteLine("Press 'q' in the terminal to quit");
while (visualizerRunning.IsSet)
{
if (Console.KeyAvailable)
{
var key = Console.ReadKey(intercept: true);
if (key.KeyChar == 'q')
{
Console.WriteLine("Closing application because user pressed 'q'");
quitRequested.Set();
Application.DoEvents();
foreach (Form form in Application.OpenForms)
{
if (form.Text.Contains("Zivid"))
{
form.Invoke(new Action(() => form.Close()));
break;
}
}
}
}
else
{
acceptEnd.Reset();
frame = camera.Capture2D3D(settings);
visualizerHandle.Show(frame);
acceptEnd.Set();
}
Thread.Sleep(10);
}
visualizationThread.Join();
Console.WriteLine("Visualizer closed");
print("Setting up visualization")
visualizer_running = threading.Event()
visualizer_running.set()
use_raw_terminal = sys.platform != "win32" and sys.stdin.isatty()
if use_raw_terminal:
old_terminal_settings = termios.tcgetattr(sys.stdin)
tty.setcbreak(sys.stdin.fileno())
try:
print("Visualizing point cloud")
with zivid.visualization.Visualizer() as visualizer:
visualizer.show(frame)
visualizer.reset_to_fit()
def _capture_and_keypress_thread() -> None:
print("Press 'q' in the terminal to quit")
while visualizer_running.is_set():
if _get_key_non_blocking() == "q":
print("Closing application because user pressed 'q'")
visualizer.close()
break
new_frame = camera.capture_2d_3d(settings)
if visualizer_running.is_set():
visualizer.show(new_frame)
time.sleep(0.01)
capture_thread = threading.Thread(target=_capture_and_keypress_thread)
capture_thread.start()
print("Running visualizer. Blocking until the window closes or 'q' is pressed.")
visualizer.run()
visualizer_running.clear()
capture_thread.join()
print("Visualizer closed")
finally:
if use_raw_terminal:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_terminal_settings)
Color Image
Zivid SDK와 Zivid-Python 은 2D 컬러 이미지 시각화를 지원하지 않기 때문에 타사 라이브러리를 사용하여 구현했습니다. C++ 및 Python에서는 OpenCV , Python에서는 Matplotlib 을 사용합니다.
OpenCV in C++ and Python
먼저 포인트 클라우드를 OpenCV 컬러 이미지로 변환합니다.
포인트 클라우드를 컬러 이미지로 변환하는 기능의 구현은 아래에 설명되어 있습니다.
팁
Zivid 2D 컬러 이미지에서 직접 OpenCV 컬러 이미지를 가져오는 것도 가능합니다.
이제 컬러 이미지를 시각화할 수 있습니다.
Matplotlib in Python
Matplotlib는 Python에서 컬러 이미지를 시각화하는 더 간단한 방법을 제공합니다.
함수 구현은 아래에 설명되어 있습니다.
Depth Map
Zivid SDK와 Zivid-Python 은 Depth 맵(Depth Map) 시각화를 지원하지 않기 때문에 타사 라이브러리를 사용하여 구현했습니다. C++ 및 Python에서는 OpenCV , Python에서는 Matplotlib 을 사용합니다.
OpenCV in C++ and Python
먼저 포인트 클라우드를 OpenCV Depth 맵으로 변환합니다.
포인트 클라우드를 Depth 맵으로 변환하는 기능의 구현은 아래에 설명되어 있습니다.
cv::Mat pointCloudToCvZ(const Zivid::PointCloud &pointCloud)
{
cv::Mat z(pointCloud.height(), pointCloud.width(), CV_8UC1, cv::Scalar(0)); // NOLINT(hicpp-signed-bitwise)
const auto points = pointCloud.copyPointsZ();
// Getting min and max values for X, Y, Z images
const auto *maxZ = std::max_element(points.begin(), points.end(), isLesserOrNan);
const auto *minZ = std::max_element(points.begin(), points.end(), isGreaterOrNaN);
// Filling in OpenCV matrix with the cloud data
for(size_t i = 0; i < pointCloud.height(); i++)
{
for(size_t j = 0; j < pointCloud.width(); j++)
{
if(std::isnan(points(i, j).z))
{
z.at<uchar>(i, j) = 0;
}
else
{
z.at<uchar>(i, j) =
static_cast<unsigned char>((255.0F * (points(i, j).z - minZ->z) / (maxZ->z - minZ->z)));
}
}
}
// Applying color map
cv::Mat zColorMap;
cv::applyColorMap(z, zColorMap, cv::COLORMAP_VIRIDIS);
// Setting invalid points (nan) to black
for(size_t i = 0; i < pointCloud.height(); i++)
{
for(size_t j = 0; j < pointCloud.width(); j++)
{
if(std::isnan(points(i, j).z))
{
auto &zRGB = zColorMap.at<cv::Vec3b>(i, j);
zRGB[0] = 0;
zRGB[1] = 0;
zRGB[2] = 0;
}
}
}
return zColorMap;
}
def _point_cloud_to_cv_z(point_cloud: zivid.PointCloud) -> np.ndarray:
"""Get depth map from frame.
Args:
point_cloud: Zivid point cloud
Returns:
depth_map_color_map: Depth map (HxWx1 ndarray)
"""
depth_map = point_cloud.copy_data("z")
depth_map_uint8 = ((depth_map - np.nanmin(depth_map)) / (np.nanmax(depth_map) - np.nanmin(depth_map)) * 255).astype(
np.uint8
)
depth_map_color_map = cv2.applyColorMap(depth_map_uint8, cv2.COLORMAP_VIRIDIS)
# Setting nans to black
depth_map_color_map[np.isnan(depth_map)[:, :]] = 0
return depth_map_color_map
이제 Depth 맵을 시각화할 수 있습니다.
Matplotlib in Python
Matplotlib는 Python에서 Depth 맵을 시각화하는 더 간단한 방법을 제공합니다.
함수 구현은 아래에 설명되어 있습니다.
def display_depthmap(xyz: np.ndarray, block: bool = True) -> None:
"""Create and display depthmap.
Args:
xyz: A numpy array of X, Y and Z point cloud coordinates
block: Stops the running program until the windows is closed
"""
plt.figure()
plt.imshow(
xyz[:, :, 2],
vmin=np.nanmin(xyz[:, :, 2]),
vmax=np.nanmax(xyz[:, :, 2]),
cmap="viridis",
)
plt.colorbar()
plt.title("Depth map")
plt.show(block=block)
Normals
Zivid SDK는 노멀/법선(Normals)의 시각화를 지원하지 않기 때문에 타사 라이브러리를 사용하여 구현했으며, C++에서 PCL , Python에서는 Open3D 를 사용합니다.
PCL in C++
다음과 같이 노멀을 시각화할 수 있습니다.
함수 구현은 아래에 설명되어 있습니다.
void visualizePointCloudAndNormalsPCL(
const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pointCloud,
const pcl::PointCloud<pcl::PointXYZRGBNormal>::ConstPtr &pointCloudWithNormals)
{
auto viewer = pcl::visualization::PCLVisualizer("Viewer");
int viewRgb(0);
viewer.createViewPort(0.0, 0.0, 0.5, 1.0, viewRgb);
viewer.addText("Cloud RGB", 0, 0, "RGBText", viewRgb);
viewer.addPointCloud<pcl::PointXYZRGB>(pointCloud, "cloud", viewRgb);
const int normalsSkipped = 10;
std::cout << "Note! 1 out of " << normalsSkipped << " normals are visualized" << std::endl;
int viewNormals(0);
viewer.createViewPort(0.5, 0.0, 1.0, 1.0, viewNormals);
viewer.addText("Cloud Normals", 0, 0, "NormalsText", viewNormals);
viewer.addPointCloud<pcl::PointXYZRGBNormal>(pointCloudWithNormals, "cloudNormals", viewNormals);
viewer.addPointCloudNormals<pcl::PointXYZRGBNormal>(
pointCloudWithNormals, normalsSkipped, 1, "normals", viewNormals);
viewer.setCameraPosition(0, 0, -100, 0, 0, 1000, 0, -1, 0);
std::cout << "Press r to centre and zoom the viewer so that the entire cloud is visible" << std::endl;
std::cout << "Press q to exit the viewer application" << std::endl;
while(!viewer.wasStopped())
{
viewer.spinOnce(100);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
}
Open3D in Python
다음과 같이 노멀을 시각화할 수 있습니다.
normals_colormap = 0.5 * (1 - normals)
normals_colormap = np.nan_to_num(normals_colormap, nan=0.0, posinf=1.0, neginf=0.0)
print("Visualizing normals in 2D")
display_rgb(rgb=rgba[:, :, :3], title="RGB image", block=False)
display_rgb(rgb=normals_colormap, title="Colormapped normals", block=True)
print("Visualizing normals in 3D")
display_pointcloud_with_downsampled_normals(point_cloud, zivid.PointCloud.Downsampling.by4x4)
함수 구현은 아래에 설명되어 있습니다.
def _copy_to_open3d_point_cloud(xyz: np.ndarray, rgb: np.ndarray, normals: np.ndarray) -> o3d.geometry.PointCloud:
"""Copy point cloud data to Open3D PointCloud object.
Args:
xyz: A numpy array of X, Y and Z point cloud coordinates
rgb: RGB image
normals: Ordered array of normal vectors, mapped to xyz
Returns:
An Open3D PointCloud object
"""
xyz = np.nan_to_num(xyz).reshape(-1, 3)
normals = np.nan_to_num(normals).reshape(-1, 3)
rgb = rgb.reshape(-1, rgb.shape[-1])[:, :3]
open3d_point_cloud = o3d.geometry.PointCloud(o3d.utility.Vector3dVector(xyz))
open3d_point_cloud.colors = o3d.utility.Vector3dVector(rgb / 255)
open3d_point_cloud.normals = o3d.utility.Vector3dVector(normals)
return open3d_point_cloud
def _display_open3d_point_cloud(open3d_point_cloud: o3d.geometry.PointCloud) -> None:
"""Display Open3D PointCloud object.
Args:
open3d_point_cloud: Open3D PointCloud object to display
"""
visualizer = o3d.visualization.Visualizer() # pylint: disable=no-member
visualizer.create_window()
visualizer.add_geometry(open3d_point_cloud)
if len(open3d_point_cloud.normals) > 0:
print("Open 3D controls:")
print(" n: for normals")
print(" 9: for point cloud colored by normals")
print(" h: for all controls")
visualizer.get_render_option().background_color = (0, 0, 0)
visualizer.get_render_option().point_size = 2
visualizer.get_render_option().show_coordinate_frame = True
visualizer.get_view_control().set_front([0, 0, -1])
visualizer.get_view_control().set_up([0, -1, 0])
visualizer.run()
visualizer.destroy_window()
def display_pointcloud_with_downsampled_normals(
point_cloud: zivid.PointCloud,
downsampling: zivid.PointCloud.Downsampling,
) -> None:
"""Display point cloud with downsampled normals.
Args:
point_cloud: A Zivid point cloud handle
downsampling: A valid Zivid downsampling factor to apply to normals
"""
point_cloud.downsample(downsampling)
rgb = point_cloud.copy_data("rgba_srgb")[:, :, :3]
xyz = point_cloud.copy_data("xyz")
normals = point_cloud.copy_data("normals")
open3d_point_cloud = _copy_to_open3d_point_cloud(xyz, rgb, normals)
_display_open3d_point_cloud(open3d_point_cloud)
Conclusion
이 튜토리얼에서는 Zivid SDK를 사용하여 C++ 및 C#에서 포인트 클라우드를 시각화하고 Python에서 시각화하기 위해 타사 라이브러리를 사용하는 방법을 보여줍니다. 타사 라이브러리를 사용하여 Python에서 포인트 클라우드를 시각화하고 C++, C# 및 Python에서 컬러 이미지, 깊이 맵 및 노멀을 시각화하는 방법을 시연합니다.