1
+ import numpy as np
2
+ import cv2
3
+ import pygame
4
+ from pygame .locals import *
5
+ from OpenGL .GL import *
6
+ from OpenGL .GLU import *
7
+
8
+ class ObjLoader :
9
+ def __init__ (self , filename , swapyz = False ):
10
+ self .vertices = []
11
+ self .normals = []
12
+ self .texcoords = []
13
+ self .faces = []
14
+ self .gl_list = None
15
+
16
+ for line in open (filename , "r" ):
17
+ if line .startswith ('#' ): continue
18
+ values = line .split ()
19
+ if not values : continue
20
+
21
+ if values [0 ] == 'v' :
22
+ v = list (map (float , values [1 :4 ]))
23
+ if swapyz :
24
+ v = v [0 ], v [2 ], v [1 ]
25
+ self .vertices .append (v )
26
+ elif values [0 ] == 'vn' :
27
+ v = list (map (float , values [1 :4 ]))
28
+ if swapyz :
29
+ v = v [0 ], v [2 ], v [1 ]
30
+ self .normals .append (v )
31
+ elif values [0 ] == 'vt' :
32
+ self .texcoords .append (list (map (float , values [1 :3 ])))
33
+ elif values [0 ] == 'f' :
34
+ face = []
35
+ texcoords = []
36
+ norms = []
37
+ for v in values [1 :]:
38
+ w = v .split ('/' )
39
+ face .append (int (w [0 ]))
40
+ if len (w ) >= 2 and len (w [1 ]) > 0 :
41
+ texcoords .append (int (w [1 ]))
42
+ else :
43
+ texcoords .append (0 )
44
+ if len (w ) >= 3 and len (w [2 ]) > 0 :
45
+ norms .append (int (w [2 ]))
46
+ else :
47
+ norms .append (0 )
48
+ self .faces .append ((face , norms , texcoords ))
49
+
50
+ def create_gl_list (self ):
51
+ if self .gl_list is not None :
52
+ return self .gl_list
53
+
54
+ self .gl_list = glGenLists (1 )
55
+ glNewList (self .gl_list , GL_COMPILE )
56
+ glFrontFace (GL_CCW )
57
+ for face in self .faces :
58
+ vertices , normals , texture_coords = face
59
+ glBegin (GL_POLYGON )
60
+ for i in range (len (vertices )):
61
+ if normals [i ] > 0 :
62
+ glNormal3fv (self .normals [normals [i ] - 1 ])
63
+ glVertex3fv (self .vertices [vertices [i ] - 1 ])
64
+ glEnd ()
65
+ glEndList ()
66
+ return self .gl_list
67
+
68
+ def render (self ):
69
+ glCallList (self .create_gl_list ())
70
+
71
+ def init_ar ():
72
+ pygame .init ()
73
+ display = (1280 , 720 )
74
+ pygame .display .set_mode (display , DOUBLEBUF | OPENGL )
75
+
76
+ glEnable (GL_DEPTH_TEST )
77
+ glEnable (GL_LIGHTING )
78
+ glLightfv (GL_LIGHT0 , GL_POSITION , (0 , 0 , - 2 , 1 ))
79
+ glLightfv (GL_LIGHT0 , GL_AMBIENT , (0.2 , 0.2 , 0.2 , 1 ))
80
+ glLightfv (GL_LIGHT0 , GL_DIFFUSE , (0.5 , 0.5 , 0.5 , 1 ))
81
+ glEnable (GL_LIGHT0 )
82
+ glEnable (GL_COLOR_MATERIAL )
83
+ glColorMaterial (GL_FRONT_AND_BACK , GL_AMBIENT_AND_DIFFUSE )
84
+
85
+ return display
86
+
87
+ def set_projection_from_camera (intrinsic ):
88
+ glMatrixMode (GL_PROJECTION )
89
+ glLoadIdentity ()
90
+
91
+ fx = intrinsic [0 ,0 ]
92
+ fy = intrinsic [1 ,1 ]
93
+ fovy = 2 * np .arctan (0.5 * 720 / fy ) * 180 / np .pi
94
+ aspect = (1280 * fy ) / (720 * fx )
95
+
96
+ gluPerspective (fovy , aspect , 0.1 , 100.0 )
97
+ glViewport (0 , 0 , 1280 , 720 )
98
+
99
+ def set_modelview_from_camera (rvec , tvec ):
100
+ glMatrixMode (GL_MODELVIEW )
101
+ glLoadIdentity ()
102
+
103
+ rotation = rvec [0 ][0 ]
104
+ translation = tvec [0 ][0 ]
105
+
106
+ rmtx = cv2 .Rodrigues (rotation )[0 ]
107
+
108
+ view_matrix = np .array ([[rmtx [0 ,0 ], rmtx [0 ,1 ], rmtx [0 ,2 ], translation [0 ]],
109
+ [rmtx [1 ,0 ], rmtx [1 ,1 ], rmtx [1 ,2 ], translation [1 ]],
110
+ [rmtx [2 ,0 ], rmtx [2 ,1 ], rmtx [2 ,2 ], translation [2 ]],
111
+ [0.0 , 0.0 , 0.0 , 1.0 ]])
112
+
113
+ view_matrix = view_matrix * np .array ([1 , - 1 , - 1 , 1 ])
114
+
115
+ inverse_matrix = np .linalg .inv (view_matrix )
116
+ glLoadMatrixf (inverse_matrix .T )
117
+
118
+ def draw_background (frame ):
119
+ glDisable (GL_DEPTH_TEST )
120
+ glMatrixMode (GL_PROJECTION )
121
+ glLoadIdentity ()
122
+ gluOrtho2D (0 , 1280 , 0 , 720 )
123
+ glMatrixMode (GL_MODELVIEW )
124
+ glLoadIdentity ()
125
+
126
+ # Convert frame to OpenGL texture format
127
+ bg_image = cv2 .flip (frame , 0 )
128
+ bg_image = cv2 .cvtColor (bg_image , cv2 .COLOR_BGR2RGB )
129
+
130
+ glEnable (GL_TEXTURE_2D )
131
+ texture_id = glGenTextures (1 )
132
+ glBindTexture (GL_TEXTURE_2D , texture_id )
133
+ glTexImage2D (GL_TEXTURE_2D , 0 , GL_RGB , 1280 , 720 , 0 , GL_RGB , GL_UNSIGNED_BYTE , bg_image )
134
+ glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR )
135
+ glTexParameteri (GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR )
136
+
137
+ # Draw textured quad
138
+ glBegin (GL_QUADS )
139
+ glTexCoord2f (0.0 , 1.0 ); glVertex2f (0 , 0 )
140
+ glTexCoord2f (1.0 , 1.0 ); glVertex2f (1280 , 0 )
141
+ glTexCoord2f (1.0 , 0.0 ); glVertex2f (1280 , 720 )
142
+ glTexCoord2f (0.0 , 0.0 ); glVertex2f (0 , 720 )
143
+ glEnd ()
144
+
145
+ glDeleteTextures ([texture_id ])
146
+ glDisable (GL_TEXTURE_2D )
147
+ glEnable (GL_DEPTH_TEST )
148
+
149
+ def main ():
150
+ cap = cv2 .VideoCapture (0 )
151
+ cap .set (cv2 .CAP_PROP_FRAME_WIDTH , 1280 )
152
+ cap .set (cv2 .CAP_PROP_FRAME_HEIGHT , 720 )
153
+
154
+ display = init_ar ()
155
+
156
+ camera_matrix = np .array ([[933.15867 , 0 , 657.59 ],
157
+ [0 , 933.1586 , 400.36993 ],
158
+ [0 , 0 , 1 ]])
159
+ dist_coeffs = np .array ([- 0.43948 , 0.18514 , 0 , 0 ])
160
+
161
+ aruco_dict = cv2 .aruco .Dictionary_get (cv2 .aruco .DICT_5X5_100 )
162
+ parameters = cv2 .aruco .DetectorParameters_create ()
163
+
164
+ obj = ObjLoader ("objects/cube.obj" , swapyz = True )
165
+
166
+ clock = pygame .time .Clock ()
167
+
168
+ # Initialize smoothing variables
169
+ smooth_rvec = None
170
+ smooth_tvec = None
171
+ smooth_factor = 0.8
172
+
173
+ while True :
174
+ for event in pygame .event .get ():
175
+ if event .type == pygame .QUIT :
176
+ pygame .quit ()
177
+ cap .release ()
178
+ return
179
+
180
+ ret , frame = cap .read ()
181
+ if not ret :
182
+ break
183
+
184
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
185
+
186
+ draw_background (frame )
187
+
188
+ gray = cv2 .cvtColor (frame , cv2 .COLOR_BGR2GRAY )
189
+ corners , ids , _ = cv2 .aruco .detectMarkers (gray , aruco_dict , parameters = parameters )
190
+
191
+ if ids is not None :
192
+ set_projection_from_camera (camera_matrix )
193
+
194
+ for i in range (len (ids )):
195
+ rvec , tvec , _ = cv2 .aruco .estimatePoseSingleMarkers (corners [i ], 0.02 , camera_matrix , dist_coeffs )
196
+
197
+ # Apply smoothing
198
+ if smooth_rvec is None :
199
+ smooth_rvec , smooth_tvec = rvec , tvec
200
+ else :
201
+ smooth_rvec = smooth_factor * smooth_rvec + (1 - smooth_factor ) * rvec
202
+ smooth_tvec = smooth_factor * smooth_tvec + (1 - smooth_factor ) * tvec
203
+
204
+ set_modelview_from_camera (smooth_rvec , smooth_tvec )
205
+
206
+ glColor3f (1.0 , 1.0 , 1.0 ) # Set color to white
207
+ glPushMatrix ()
208
+ glScalef (0.005 , 0.005 , 0.005 ) # Scale down the cube
209
+ obj .render ()
210
+ glPopMatrix ()
211
+
212
+ pygame .display .flip ()
213
+ clock .tick (60 )
214
+
215
+ if __name__ == "__main__" :
216
+ main ()
0 commit comments