从相机获取每个像素的深度

Posted

技术标签:

【中文标题】从相机获取每个像素的深度【英文标题】:Get depth from camera for each pixel 【发布时间】:2013-07-15 16:42:36 【问题描述】:

我有一个网格模型,并使用 VTK 从给定的相机位置 (x,y,z) 渲染了它的视图。我可以将其保存到 RGB 图像 (640x480),但我还想保存深度图,其中每个像素存储来自相机的深度值。

我已经尝试使用由渲染窗口给出的Zbuffer 值,遵循this example。问题是Zbufer 仅存储范围 [0,1] 中的值。相反,我正在尝试创建合成范围图像,在其中存储每个像素与相机的深度/距离。类似于 Kinect 生成的图像,我试图从网格模型的特定视点创建一个。

编辑 - 添加一些代码

我当前的代码:

加载网格

string mesh_filename = "mesh.ply";
    vtkSmartPointer<vtkPLYReader> mesh_reader = read_mesh_ply(mesh_filename);

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(mesh_reader->GetOutputPort());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    vtkSmartPointer<vtkRenderer> renderer =  vtkSmartPointer<vtkRenderer>::New();
    vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
    renderWindow->AddRenderer(renderer);
    renderWindow->SetSize(640, 480);

    vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
    renderWindowInteractor->SetRenderWindow(renderWindow);

    //Add the actors to the scene
    renderer->AddActor(actor);
    renderer->SetBackground(1, 1, 1);

创建一个相机并将其放置在某处

vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();

    renderer->SetActiveCamera(camera);
    camera->SetPosition(0,0,650);
    //Render and interact
    renderWindow->Render();

从 z 缓冲区获取结果

double b = renderer->GetZ(320, 240);

在本例中,这给出了 0.999995。由于值在 [0,1] 之间,我不知道如何解释,如您所见,我已将相机设置为在 z 轴上 650 个单位,因此我假设该像素的 z 距离(在渲染 RGB 中的对象上)应该接近 650。

【问题讨论】:

你读过这个吗? vtk.org/Wiki/VTK/Examples/Cxx/Utilities/ZBuffer @TomásBadan 嗨,是的,我已阅读此示例。问题是 zbufer 只存储 [0,1] 范围内的值。相反,我正在尝试创建合成范围图像,在那里我可以从相机中获取每个像素的深度/距离。 (使用此评论编辑问题) 在 openGL 中,z 缓冲区以单一值给出,其中 1 表示尽可能远,0 表示尽可能近。你确定这个缓冲区也不是单一的吗? @TomásBadan 是的,这就是问题所在。有没有办法将此数字转换为“真实”深度,即模型单位? 阿德里安发布的公式仅适用于正交投影。对于透视投影,z 缓冲区不是线性的。我的猜测是,这就是 SetInputBufferTypeToZBuffer() 方法应该处理的问题。 【参考方案1】:

这个 python sn-p 说明了如何将 z 缓冲区值转换为实际距离。非线性映射定义如下:

numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator

这里是一个完整的例子:

import vtk
import numpy as np
from vtk.util import numpy_support
import matplotlib.pyplot as plt

vtk_renderer = vtk.vtkRenderer()
vtk_render_window = vtk.vtkRenderWindow()
vtk_render_window.AddRenderer(vtk_renderer)
vtk_render_window_interactor = vtk.vtkRenderWindowInteractor()
vtk_render_window_interactor.SetRenderWindow(vtk_render_window)
vtk_render_window_interactor.Initialize()

source = vtk.vtkCubeSource()
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(source.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.RotateX(60.0)
actor.RotateY(-35.0)
vtk_renderer.AddActor(actor)

vtk_render_window.Render()
active_vtk_camera = vtk_renderer.GetActiveCamera()
z_near, z_far = active_vtk_camera.GetClippingRange()

z_buffer_data = vtk.vtkFloatArray()
width, height = vtk_render_window.GetSize()
vtk_render_window.GetZbufferData(
    0, 0, width - 1, height - 1, z_buffer_data)
z_buffer_data_numpy = numpy_support.vtk_to_numpy(z_buffer_data)
z_buffer_data_numpy = np.reshape(z_buffer_data_numpy, (-1, width))
z_buffer_data_numpy = np.flipud(z_buffer_data_numpy)  # flipping along the first axis (y)

numerator = 2.0 * z_near * z_far
denominator = z_far + z_near - (2.0 * z_buffer_data_numpy - 1.0) * (z_far - z_near)
depth_buffer_data_numpy = numerator / denominator
non_depth_data_value = np.nan
depth_buffer_data_numpy[z_buffer_data_numpy == 1.0] = non_depth_data_value

print(np.nanmin(depth_buffer_data_numpy))
print(np.nanmax(depth_buffer_data_numpy))

plt.imshow(np.asarray(depth_buffer_data_numpy))
plt.show()

旁注: 在我的系统上,有几次imshow 命令没有显示任何内容。重新运行脚本确实解决了这个问题。

来源:

http://web.archive.org open3d

【讨论】:

非常好,我还建议使用 vtkWindowToImageFilter 来获取 ZBuffer 而不是直接从渲染窗口获取它

以上是关于从相机获取每个像素的深度的主要内容,如果未能解决你的问题,请参考以下文章

从相机意图中获取像素的颜色

iOS:从相机获取逐像素数据

从实时相机预览中获取特定像素的颜色 - Ionic

从相机设备获取号码

OpenGL获取像素的原始3d坐标

如何从深度相机获取世界系统中的深度坐标