主要理解代码 + 记录解决报错问题,具体内容有空补上。
在 OpenGL 中主要使用 4x4 矩阵来表示转换,这个和 3x4 的相机矩阵不同。然而,OpenGL 中的 GL_PROJECTION 和 GL_MODELVIEW 是将相机矩阵分开来表示。其中 GL_PROJECTION 表示相机的内参数 K 矩阵;GL_MODELVIEW 表示物体和相机之间的转换关系,可以粗略地表示为 R 和 t 矩阵。
代码如下所示, K 表示校准后的相机内参数矩阵。
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame, pygame.image
from pygame.locals import *
from OpenGL.GLUT import *
import numpy as np
from scipy import linalg
import sys
def set_projection_from_camera(K):
"""
Set view from a camera calibration matrix.
"""
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
fx = K[0, 0]
fy = K[1, 1]
# 计算以度为单位的垂直视野
fovy = 2*np.arctan(0.5*height/fy)*180/np.pi
# 纵横比
aspect = (width*fy)/(height*fx)
# define the near and far clipping planes
near = 0.1
far = 100.0
# set perspective
gluPerspective(fovy, aspect, near, far)
glViewport(0, 0, width, height)
P = K[R|t],所以 Rt = PK-1 得到。Rt 为下面代码的输入:
def set_modelview_from_camera(Rt):
"""
Set the model view matrix from camera pose.
"""
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
# rotate teapot 90 deg around x-axis so that z-axis is up
Rx = np.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])
# set rotation to best approximation
R = Rt[:, :3]
U, S, V = linalg.svd(R)
R = np.dot(U, V)
R[0, :] = -R[0, :] # change sign of x-axis
# set translation
t = Rt[:, 3]
# set 4*4 model view matrix
M = np.eye(4)
M[:3, :3] = np.dot(R, Rx)
M[:3, 3] = t
# transpose and flatten to grt column order
M = M.T
m = M.flatten()
# replace model view with new matrix
glLoadMatrixf(m)
def draw_background(imname):
"""
Draw background image using a quadrilateral.
"""
# load backgound image (should be .bmp) to OpenGL texture
bg_image = pygame.image.load(imname).convert()
bg_data = pygame.image.tostring(bg_image, "RGBX", 1)
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# bind the texture
glEnable(GL_TEXTURE_2D)
glBindTexture(GL_TEXTURE_2D, glGenTextures(1))
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bg_data)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
# create quad to fill the whole window
glBegin(GL_QUADS)
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0)
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0)
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0)
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0)
glEnd()
# clear the texture
glDeleteTextures(1)
def draw_teapot(size):
"""
Draw a red teapot at the origin.
"""
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
glClear(GL_DEPTH_BUFFER_BIT)
# draw red teapot
glMaterialfv(GL_FRONT,GL_AMBIENT,[0,0,0,0])
glMaterialfv(GL_FRONT,GL_DIFFUSE,[0.5,0.0,0.0,0.0])
glMaterialfv(GL_FRONT,GL_SPECULAR,[0.7,0.6,0.6,0.0])
glMaterialf(GL_FRONT,GL_SHININESS,0.25*128.0)
glutSolidTeapot(size)
主代码:
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import pygame, pygame.image
from pygame.locals import *
import pickle
width, height = 1000, 747
def setup():
"""
Setup window and pygame environment.
"""
pygame.init()
pygame.display.set_mode((width, height), OPENGL | DOUBLEBUF)
pygame.display.set_caption('OpenGL AR demo')
# load camera data
with open('ar_camera.pkl', 'rb') as f:
K = pickle.load(f)
Rt = pickle.load(f)
setup()
draw_background('./book_perspective.bmp')
set_projection_from_camera(K)
set_modelview_from_camera(Rt)
draw_teapot(0.05)
pygame.display.flip()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.quit()
pygame.display.flip()
结果:
OpenGL.error.NullFunctionError:
Attempt to call an undefined function glutSolidTeapot, check for bool(glutSolidTeapot) before calling
解决方法:
pip
安装的 PyOpenGL
;Python
版本的 .whl
文件;pip install xxxx.whl
freeglut ERROR: Function <glutSolidTeapot> called without first calling 'glutInit'.
这个错误是freeglut和glut共存的缘故,它们俩定义了相同的方法,这个是动态链接库的重叠问题,找到你使用的python路径下\OpenGL\DLLS中的glut64.vcX.dll文件,将其余文件删除就可以了。
[1]. Programming Computer Vision with Python
[2]. python照相机模型与增强现实
[3]. 【计算机视觉】照相机模型与增强现实