从OpenGL深度缓冲区获取世界坐标

时间:2019-12-01 18:58:35

标签: python c++ opengl depth-buffer

我正在使用pyBullet,这是bullet3物理引擎的python包装器,我需要从虚拟相机创建点云。
该引擎使用基本的OpenGL渲染器,我能够从OpenGL深度缓冲区中获取值

img = p.getCameraImage(imgW, imgH, renderer=p.ER_BULLET_HARDWARE_OPENGL)
rgbBuffer = img[2]
depthBuffer = img[3]

现在,我有了带有深度值的width * height数组。如何从中获取世界坐标?我试图用点(宽度,高度,depthBuffer(宽度,高度))保存.ply点云,但这不会创建看起来像场景中对象的点云。

我还试图用近距离平面校正深度:

depthImg = float(depthBuffer[h, w])
far = 1000.
near = 0.01
depth = far * near / (far - (far - near) * depthImg)

但是这样做的结果也是一些怪异的点云。如何从深度缓冲区中的数据创建逼真的点云?甚至有可能吗?

我在c ++中做了类似的事情,但在那里我使用了glm :: unproject

for (size_t i = 0; i < height; i = i = i+density) {
        for (size_t j = 0; j < width; j = j = j+density) {

            glm::vec3 win(i, j, depth);
            glm::vec4 position(glm::unProject(win, identity, projection, viewport), 0.0);

编辑:

基于Rabbid76的答案,我使用了有效的PyGLM,现在我可以获取XYZ世界坐标来创建点云,但是点云中的深度值看起来失真了,我是否可以正确地从深度缓冲区获取深度?

    for h in range(0, imgH, stepX):
       for w in range(0, imgW, stepY):
          depthImg = float(np.array(depthBuffer)[h, w])
          far = 1000.
          near = 0.01
          depth = far * near / (far - (far - near) * depthImg)
          win = glm.vec3(h, w, depthBuffer[h][w])
          position = glm.unProject(win, model, projGLM, viewport)
          f.write(str(position[0]) + " " + str(position[1]) + " " + str(depth) + "\n")

1 个答案:

答案 0 :(得分:1)

这是我的解决方案。我们只需要知道视图矩阵和投影矩阵是如何工作的。 pybullet中有computeProjectionMatrixFOV和computeViewMatrix函数。 http://www.songho.ca/opengl/gl_projectionmatrix.htmlhttp://ksimek.github.io/2012/08/22/extrinsic/ 一句话,point_in_world = inv(projection_matrix * viewMatrix)* NDC_pos

glm.unProject是另一个解决方案

    stepX = 10
    stepY = 10        
    pointCloud = np.empty([np.int(img_height/stepY), np.int(img_width/stepX), 4])
    projectionMatrix = np.asarray(projection_matrix).reshape([4,4],order='F')
    viewMatrix = np.asarray(view_matrix).reshape([4,4],order='F')
    tran_pix_world = np.linalg.inv(np.matmul(projectionMatrix, viewMatrix))
    for h in range(0, img_height, stepY):
        for w in range(0, img_width, stepX):
            x = (2*w - img_width)/img_width
            y = -(2*h - img_height)/img_height  # be careful! deepth and its corresponding position
            z = 2*depth_np_arr[h,w] - 1
            pixPos = np.asarray([x, y, z, 1])
            position = np.matmul(tran_pix_world, pixPos)

            pointCloud[np.int(h/stepY),np.int(w/stepX),:] = position / position[3]