这次试验主要实现以平面和标记物进行姿态估计以及增强现实的应用。

一、以平面和标记物进行姿态估计
(1)下面演示的是一个简单例子:如何在一副图像上放置一个立方体,原图如下:

(2)先提取两幅JPG图像的SIFT特征,然后使用RANSAC算法稳健地估计单应性矩阵,这两个算法前面的博文都有介绍,代码参考《python计算机视觉编程》,按如下运行一般不会有什么问题。
代码:

# -*- coding: utf-8 -*-
from pylab import *
from PIL import Image

# If you have PCV installed, these imports should work
from PCV.geometry import homography, camera
from PCV.localdescriptors import sift

"""
This is the augmented reality and pose estimation cube example from Section 4.3.
"""

def cube_points(c, wid):
""" 创建用于绘制立方体的一个点列表(前5个点是底部的正方形,一些边重合了) """
p = []
# bottom
p.append([c[0]-wid, c[1]-wid, c[2]-wid])
p.append([c[0]-wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]-wid, c[2]-wid])
p.append([c[0]-wid, c[1]-wid, c[2]-wid]) #same as first to close plot

# top
p.append([c[0]-wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]-wid, c[2]+wid]) #same as first to close plot

# vertical sides
p.append([c[0]-wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]-wid])

return array(p).T

def my_calibration(sz):
"""根据自己图像的分辨率修改这个函数中的数值"""
"""
Calibration function for the camera (iPhone4) used in this example.
"""
row, col = sz
fx = 2555*col/2592
fy = 2586*row/1936
K = diag([fx, fy, 1])
K[0, 2] = 0.5*col
K[1, 2] = 0.5*row
return K

#计算特征
sift.process_image('image4/book_frontal.JPG', 'im0.sift')
l0, d0 = sift.read_features_from_file('im0.sift')

sift.process_image('image4/book_perspective.JPG', 'im1.sift')
l1, d1 = sift.read_features_from_file('im1.sift')

# 匹配特征,并计算单应性矩阵
matches = sift.match_twosided(d0, d1)
ndx = matches.nonzero()[0]
fp = homography.make_homog(l0[ndx, :2].T)
ndx2 = [int(matches[i]) for i in ndx]
tp = homography.make_homog(l1[ndx2, :2].T)

model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)

# 计算照相机标定矩阵
K = my_calibration((747, 1000))

# 位于边长为0.2,z=0平面上的三维点
box = cube_points([0, 0, 0.1], 0.1)

# 投影第一幅图像上底部的正方形
cam1 = camera.Camera(hstack((K, dot(K, array([[0], [0], [-1]])))))
# 底部正方形上的点
box_cam1 = cam1.project(homography.make_homog(box[:, :5]))

# 使用H将点变换到第二幅图像中
box_trans = homography.normalize(dot(H,box_cam1))

# 从cam1和H中计算第二个照相机矩阵
cam2 = camera.Camera(dot(H, cam1.P))
A = dot(linalg.inv(K), cam2.P[:, :3])
A = array([A[:, 0], A[:, 1], cross(A[:, 0], A[:, 1])]).T
cam2.P[:, :3] = dot(K, A)

# 使用第二个照相机矩阵投影
box_cam2 = cam2.project(homography.make_homog(box))
'''
with open('ar_camera.pkl','r') as f:
pickle.dump(k,f)
pickle.dump(dot(linalg.inv(K),cam2.p),f)
'''
# 绘制
im0 = array(Image.open('image4/book_frontal.JPG'))
im1 = array(Image.open('image4/book_perspective.JPG'))

figure()
imshow(im0)
plot(box_cam1[0, :], box_cam1[1, :], linewidth=3)
title('2D projection of bottom square')
axis('off')

figure()
imshow(im1)
plot(box_trans[0, :], box_trans[1, :], linewidth=3)
title('2D projection transfered with H')
axis('off')

figure()
imshow(im1)
plot(box_cam2[0, :], box_cam2[1, :], linewidth=3)
title('3D points projected in second image')
axis('off')

show()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(3)运行结果

可以看到在书的平面上建立起了一个正方体,这三幅实验图的分辨率都是747×1000,若是所用的图片分辨率有所变化,则需要在代码中K = my_calibration((747, 1000))这一部分做相应的修改。

二、增强现实
(1)运行准备
增强现实是将物体和相应信息放置在图像数据上的一系列操作的总称,也就是大家熟悉的AR。在这里我们需要用到两个工具包:PyGame和PyOpenGL。这里给出下载地址:
https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyopengl
http://www.lfd.uci.edu/~gohlke/pythonlibs/#pygame
在安装这两个工具包之前,先查看一下自己所用的版本信息,下载对应的包的版本,若是版本不对应则会出现is not a supported wheel on this platform这样的报错。
具体操作如下:
1.打开cmd,输入python,则会显示对应版本信息。

2.输入import pip._internal,回车。

3.继续输入print(pip._internal.pep425tags.get_supported()),则会显示相对应的信息。

我这里所使用的是32位的python27版本,也就是说我们所需要安装的包的版本应是如上格式的,在这里我直接在命令行pip install pygame就可以下载,下载下来的就是32位的,若版本是64位的,那么就需要去官网下载pygame‑1.9.4‑cp27‑cp27m‑win_amd64.whl,安装过程很简单,进入所在目录pip就行。

(2)完成包的导入后,我用python脚本开始运行代码,碰到了如下几个问题。

1.opengl的窗口弹出后便闪退了,但是shell里并没有报错,我一开始以为是版本的问题,尝试换了一些版本,但是结果都是一样的,便改用cmd运行,发现出现了如下的报错:

有人提醒这个错误是freeglut和glut共存的缘故,它们俩定义了相同的方法,这个是动态链接库的重叠问题,在我的电脑中需要到C:\Python27\Lib\site-packages\OpenGL\DLLS中删除重复的dll文件,只剩下glut32.vc9.dll这个文件就行。

2.下面第一个错误就是单纯的图片不过关的问题了,这里要注意的是在选用图片时,一定要将分辨率以及代码中的宽高设定就行修改,第二个错误就是因为没有仔细修改代码中对应图片的数据造成的。

(3)运行结果
我先用与上面的相同的图片做了测试,发现能够呈现与书中相同的效果

那么就可以进一步地尝试自己拍摄的图片,选用测试图片如下:

1.失败结果

这两张图的结果显示就是上面所说的图片数据没有改好,代码中的宽高要根据你所用的图片来设定,若是不一致则可能出现上面这样成功率为0的情况。

2.成功结果

上面这组所选用的图片分辨率为1080×1440,我的电脑的分辨率为1366×768,所以高度上显示不完全,但是不怎么影响实验结果。若是想要显示完全,还需要调整自己的图片和代码,将其改成1000×747,调整后结果如下:

(4)代码

import math
import pickle
from pylab import *
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import pygame, pygame.image
from pygame.locals import *
from PCV.geometry import homography, camera
from PCV.localdescriptors import sift

def cube_points(c, wid):
""" Creates a list of points for plotting
a cube with plot. (the first 5 points are
the bottom square, some sides repeated). """
p = []
# bottom
p.append([c[0]-wid, c[1]-wid, c[2]-wid])
p.append([c[0]-wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]-wid, c[2]-wid])
p.append([c[0]-wid, c[1]-wid, c[2]-wid]) #same as first to close plot

# top
p.append([c[0]-wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]-wid, c[2]+wid]) #same as first to close plot

# vertical sides
p.append([c[0]-wid, c[1]-wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]+wid])
p.append([c[0]-wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]-wid])
p.append([c[0]+wid, c[1]+wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]+wid])
p.append([c[0]+wid, c[1]-wid, c[2]-wid])

return array(p).T

def my_calibration(sz):
row, col = sz
fx = 2555*col/2592
fy = 2586*row/1936
K = diag([fx, fy, 1])
K[0, 2] = 0.5*col
K[1, 2] = 0.5*row
return K

def set_projection_from_camera(K):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
fx = K[0,0]
fy = K[1,1]
fovy = 2*math.atan(0.5*height/fy)*180/math.pi
aspect = (width*fy)/(height*fx)
near = 0.1
far = 100.0
gluPerspective(fovy,aspect,near,far)
glViewport(0,0,width,height)

def set_modelview_from_camera(Rt):
glMatrixMode(GL_MODELVIEW)
glLoadIdentity()
Rx = np.array([[1,0,0],[0,0,-1],[0,1,0]])
R = Rt[:,:3]
U,S,V = np.linalg.svd(R)
R = np.dot(U,V)
R[0,:] = -R[0,:]
t = Rt[:,3]
M = np.eye(4)
M[:3,:3] = np.dot(R,Rx)
M[:3,3] = t
M = M.T
m = M.flatten()
glLoadMatrixf(m)

def draw_background(imname):
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)
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)
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()
glDeleteTextures(1)

def draw_teapot(size):
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
glEnable(GL_DEPTH_TEST)
glClear(GL_DEPTH_BUFFER_BIT)
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)

width,height = 1000,747 #根据图片修改
def setup():
pygame.init()
pygame.display.set_mode((width,height),OPENGL | DOUBLEBUF)
pygame.display.set_caption("OpenGL AR demo")

# compute features
sift.process_image('python6.jpg', 'im0.sift')
l0, d0 = sift.read_features_from_file('im0.sift')

sift.process_image('python7.jpg', 'im1.sift')
l1, d1 = sift.read_features_from_file('im1.sift')

# match features and estimate homography
matches = sift.match_twosided(d0, d1)
ndx = matches.nonzero()[0]
fp = homography.make_homog(l0[ndx, :2].T)
ndx2 = [int(matches[i]) for i in ndx]
tp = homography.make_homog(l1[ndx2, :2].T)

model = homography.RansacModel()
H, inliers = homography.H_from_ransac(fp, tp, model)

K = my_calibration((747, 1000))
cam1 = camera.Camera(hstack((K, dot(K, array([[0], [0], [-1]])))))
box = cube_points([0, 0, 0.1], 0.1)
box_cam1 = cam1.project(homography.make_homog(box[:, :5]))
box_trans = homography.normalize(dot(H,box_cam1))
cam2 = camera.Camera(dot(H, cam1.P))
A = dot(linalg.inv(K), cam2.P[:, :3])
A = array([A[:, 0], A[:, 1], cross(A[:, 0], A[:, 1])]).T
cam2.P[:, :3] = dot(K, A)

Rt=dot(linalg.inv(K),cam2.P)

setup()
draw_background("python7.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(http://www.my516.com):
if event.type == pygame.QUIT:
sys.exit()
pygame.quit()
pygame.display.flip()
---------------------

python照相机模型与增强现实的更多相关文章

  1. OpenGL边用边学------2 经典照相机模型

    https://blog.csdn.net/smstong/article/details/50290327 实际照相步骤 1 布置场景和调整照相机位置 3 选择镜头对焦Focus 4 按下快门 5 ...

  2. python sklearn模型的保存

    使用python的机器学习包sklearn的时候,如果训练集是固定的,我们往往想要将一次训练的模型结果保存起来,以便下一次使用,这样能够避免每次运行时都要重新训练模型时的麻烦. 在python里面,有 ...

  3. python django模型内部类meta详细解释

    Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.下面对此作一总结: abstract      这个属性是定义当前的模型类是不是一个抽象类.所谓抽象类是不会相应 ...

  4. Python Select模型(程序流程)(转)

    缘由 之前写socket的CS模型代码,都是利用最原始的多线程方式.服务端是主线程,接到客户端的连接请求就从线程池中获取一个线程去处理整个socket连接的所有操作,虽然在连接数较短的情况下没有什么影 ...

  5. 玩转python主题模型程序库gensim

    gensim是python下一个极易上手的主题模型程序库(topic model),网址在:http://radimrehurek.com/gensim/index.html 安装过程较为繁琐,参考h ...

  6. 用PMML实现python机器学习模型的跨平台上线

    python信用评分卡(附代码,博主录制) https://study.163.com/course/introduction.htm?courseId=1005214003&utm_camp ...

  7. Python 存储模型

    1.Python彻底分离了对象和引用,可以认为内存中的对象都是不可修改的,每次修改引用,相当于在堆上重新创建一个对象,引用指向新对象. 2.对于数值和字符串,修改意味着引用指向一个新对象. 3.集合中 ...

  8. Python IO模型

    这篇博客是本人借鉴一些大神的博客并结合自己的学习过程写下的. 事件驱动模型 事件驱动模型是一种编程范式,这里程序的执行流由外部事件来决定.它的特点是包含一个事件循环,当外部事件发生时,不断从队列里取出 ...

  9. python 编程模型

    数据模型(译)   image.png 1 对象(object).类型(type)和值(value) python中所有的数据都是通过对象(object)或者对象之间的关系来表示 每个对象(objec ...

随机推荐

  1. 什么是以太坊私钥储存(Keystore)文件

    进入keystore管理以太坊私钥的障碍很大,主要是因为以太坊客户端在直接的命令行或图形界面下隐藏了大部分的密码复杂性. 例如,用geth: $ geth account new Your new a ...

  2. String模块ascii_letters和digits

    Python3中String模块ascii_letters和digits方法,其中ascii_letters是生成所有字母,从a-z和A-Z,digits是生成所有数字0-9. 示例如下: Pytho ...

  3. 【转】python中获得当前目录和上级目录

    原文地址:http://blog.csdn.net/liuweiyuxiang/article/details/71154346 获取当前文件的路径: from os import path d = ...

  4. bzoj3638

    费用流+线段树 看见这个题我们马上就能想到费用流,设立源汇,分别向每个点连接容量为1费用为0的边,然后相邻的点之间连边,费用为点权,跑费用流就行了,但是很明显这样会超时,那么我们要优化一下,我们观察费 ...

  5. 在Centos下安装httpd、php、Mysql并配置(转载)

    转自:http://club.jledu.gov.cn/?action-viewspace-itemid-299020 1.安装Apahce, PHP, Mysql, 以及php连接mysql库组件. ...

  6. 用set和shopt设置bash选项

    1.set命令 -o打开选项,+o关闭选项#set -o //显示选项设置#set -o noclobber //打开该选项,重定向将覆盖已存在的文件#set +o noclobber //关闭该选项 ...

  7. X86 Linux 下 SIGBUS 总结

    SIGBUS 在 x86 Linux 上并不多见,但一旦出现,其调用堆栈常常让人摸不着头脑,加之信号问题各平台系统间差异较大,更让人难以理清,这里稍微总结一下 x86 Linux 上大概有哪些情形会触 ...

  8. Tian Ji -- The Horse Racing HDU - 1052

    Tian Ji -- The Horse Racing HDU - 1052 (有平局的田忌赛马,田忌赢一次得200块,输一次输掉200块,平局不得钱不输钱,要使得田忌得到最多(如果只能输就输的最少) ...

  9. JEECMS9.3集成dubbo操作记录

    需求描述: 门户及其他应用系统需要查询JEECMS9.3中发布的栏目及数据,而其他系统都是基于dubbo开发的,因此想要将JEECMS9.3中集成dubbo并对外提供内容管理服务. 需求实现: 1.添 ...

  10. iOS开发之邮件发送代码

    邮件发送功能是由MessageUI Framework提供的,这个框架是iPhone sdk中最简单的框.由一个类.一个视图控制器,一个protocol组成. 一.创建视图控制器: MFMailCom ...