получить 3d точку в пространстве, используя 2d точку в изображении в python opengl - PullRequest
0 голосов
/ 20 мая 2018

Я пытаюсь смоделировать камеру глубины в комнате, моя камера может перемещаться и вращаться в мире, и комната имитируется как трехмерный куб вокруг (0,0,0). Нажатием кнопки Iхочу сделать выборку из N случайных точек на изображении и получить расстояние до этих точек от камеры (расстояние в «реальном мире»).До сих пор мне удалось создать сцену из движущейся камеры и куба ( Пример )

Я попытался gluUnProject, чтобы получить 3d точку

model_view = np.array(glGetDoublev(GL_MODELVIEW_MATRIX))
proj = np.array(glGetDoublev(GL_PROJECTION_MATRIX))
view = np.array(glGetDoublev(GL_VIEWPORT))

3d_point = gluUnProject(x,y, 0.0)

, гдеx, y - координаты пикселя на изображении, но когда я проверяю это на пикселях, которые я знаю их местоположение (углы куба), я получаю то, что кажется случайным результатом.

Я очень новичок в openGL, так чтоЯ мог бы что-то упустить, по математике все, что я хочу сделать, это применить инверсию матрицы проекции и вида к координатам пикселей, но это не работает.

Я прилагаю код для симуляции комнаты ниже.

Заранее спасибо.

import pygame
from pygame.locals import *
import numpy as np
import random
from OpenGL.GL import *
from OpenGL.GLU import *
display = (800, 600)
import math

def get_cube_information():

    vertices = (
        (1, -1, -1),
        (1, 1, -1),
        (-1, 1, -1),
        (-1, -1, -1),
        (1, -1, 1),
        (1, 1, 1, ),
        (-1, -1, 1),
        (-1, 1, 1),
        )

    edges = (
        (0,1),
        (0,3),
        (0,4),
        (2,1),
        (2,3),
        (2,7),
        (6,3),
        (6,4),
        (6,7),
        (5,1),
        (5,4),
        (5,7),
        )

    surfaces = (
        (0,1,2,3),
        (3,2,7,6),
        (6,7,5,4),
        (4,5,1,0),
        (1,5,7,2),
        (4,0,3,6),
        )

    colors = (
        (1.000, 0.920, 0.000),
        (0.000, 0.860, 0.000),
        (1.000, 0.480, 0.000),
        (1.000, 1.000, 1.000),
        (0.900, 0.000, 0.000),
        (0.000, 0.000, 0.950)
    )
    return vertices, edges, surfaces, colors


def Cube():
    glBegin(GL_QUADS)

    (vertices, edges, surfaces, colors) = get_cube_information()
    for i, surface in enumerate(surfaces):
        x = 0
        color = colors[i]
        for vertex in surface:
            x += 1
            glColor3fv(color)
            glVertex3fv(vertices[vertex])


    glEnd()

    glBegin(GL_LINES)
    for edge in edges:
        for vertex in edge:
            glVertex3fv(vertices[vertex])

    glEnd()


def main():
    pygame.init()
    tx = 0
    ty = 0
    tz = 0
    ry = 0
    rx = 0
    pygame.display.set_mode(display, DOUBLEBUF|OPENGL|RESIZABLE)

    glMatrixMode(GL_PROJECTION)
    gluPerspective(45, (display[0] / display[1]), 0.1, 50.0)

    view_mat = np.matrix(np.identity(4), copy=False, dtype='float32')

    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()
    glTranslatef(0, 0, 0)
    glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
    glLoadIdentity()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    quit()
                if event.key == pygame.K_a:
                    tx = 0.05
                elif event.key == pygame.K_d:
                    tx = -0.05
                elif event.key == pygame.K_w:
                    tz = 0.05
                elif event.key == pygame.K_s:
                    tz = -0.05
                elif event.key == pygame.K_RIGHT:
                    ry = 1.0
                elif event.key == pygame.K_LEFT:
                    ry = -1.0
                elif event.key == pygame.K_UP:
                    rx = -1.0
                elif event.key == pygame.K_DOWN:
                    rx = 1.0
                elif event.key == pygame.K_SPACE:
                    continue
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_a and tx > 0:
                    tx = 0
                elif event.key == pygame.K_d and tx < 0:
                    tx = 0
                elif event.key == pygame.K_w and tz > 0:
                    tz = 0
                elif event.key == pygame.K_s and tz < 0:
                    tz = 0
                elif event.key == pygame.K_RIGHT and ry > 0:
                    ry = 0.0
                elif event.key == pygame.K_LEFT and ry < 0:
                    ry = 0.0
                elif event.key == pygame.K_DOWN and rx > 0:
                    rx = 0.0
                elif event.key == pygame.K_UP and rx < 0:
                    rx = 0.0
            elif event.type == pygame.MOUSEBUTTONDOWN:
                #here I want to sample the points and return their (x,y) in the image and their distance from the camera.
                continue

        glPushMatrix()
        glLoadIdentity()
        glTranslatef(tx, ty, tz)
        glRotatef(ry, 0, 1, 0)
        glRotatef(rx, 1, 0, 0)

        glMultMatrixf(view_mat)
        glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        Cube()
        glPopMatrix()
        pygame.display.flip()
        pygame.time.wait(10)
main()

1 Ответ

0 голосов
/ 20 мая 2018

Чтобы найти мировую позицию точки в окне просмотра, необходимо знать значение глубины точки.

Положение экрана x и y и глубина были преобразованы в нормализованные координаты устройства вдиапазон [-1, 1].Для этого должен быть известен прямоугольник области просмотра:

ndc = [2.0* x/vp_width - 1.0, 1.0 - 2.0*y/vp_height, depth*2.0 - 1.0]; 

Нормализованная пространственная координата устройства должна быть преобразована с помощью матрицы обратной проекции в пространство вида (наконец, необходимо выполнить деление перспективы).

С помощью матрицы обратного вида координату пространства обзора можно преобразовать в мировое пространство.

gluUnProject делает все это за вас, но вы должны знать глубинуфрагмент.Глубина фрагмента может быть прочитана с помощью glReadPixels:

# get mouse position
x, y = pygame.mouse.get_pos()

# get the fragment depth
depth = glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT)

# get projection matrix, view matrix and the viewport rectangle
model_view = np.array(glGetDoublev(GL_MODELVIEW_MATRIX))
proj = np.array(glGetDoublev(GL_PROJECTION_MATRIX))
view = np.array(glGetIntegerv(GL_VIEWPORT))

# unproject the point
point = gluUnProject(x, y, depth, model_view, proj, view)
print( point )

Обратите внимание, вы должны включить Проверка глубины в противном случае буфер глубиныне будет установлен.Это также дает то преимущество, что многоугольники на передней панели покрывают многоугольники «позади»:

glEnable(GL_DEPTH_TEST)
Cube()

Конечно, матрица проекции и матрица вида модели должны быть правильно установлены, когда значениячитаются glGetDoublev(GL_PROJECTION_MATRIX) соответственно glGetDoublev(GL_MODELVIEW_MATRIX).

Это означает, что чтение матрицы вида должно быть выполнено после ее установки:

glPushMatrix()
glLoadIdentity()
glTranslatef(tx, ty, tz)
glRotatef(ry, 0, 1, 0)
glRotatef(rx, 1, 0, 0)

glMultMatrixf(view_mat)
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat)

model_view = np.array(glGetDoublev(GL_MODELVIEW_MATRIX))

Обратите внимание, если для 4-го параметра (model) из gluUnProject используется единичная матрица, тогда gluUnProject не вычисляет мировые координаты, но вычисляет координаты вида.

...