# A simple augmented reality application

#### 相机矩阵转换成 OpenGL 格式

``````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)

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-1Rt 为下面代码的输入：

``````
def set_modelview_from_camera(Rt):

"""
Set the model view matrix from camera pose.
"""
glMatrixMode(GL_MODELVIEW)

# 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
``````

#### 将虚拟物体投放到图片上

``````def draw_background(imname):

"""
Draw background image using a quadrilateral.
"""

# load backgound image (should be .bmp) to OpenGL texture
bg_data = pygame.image.tostring(bg_image, "RGBX", 1)

glMatrixMode(GL_MODELVIEW)
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
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')

with open('ar_camera.pkl', 'rb') as 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
``````

1. 卸载用 `pip` 安装的 `PyOpenGL`
2. https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载对应 `Python` 版本的 `.whl` 文件；
3. 重新安装：`pip install xxxx.whl`
• 报错二
``````freeglut  ERROR:  Function <glutSolidTeapot> called without first calling 'glutInit'.
``````

#### 参考

[1]. Programming Computer Vision with Python

[2]. python照相机模型与增强现实