├── README.md ├── VR_Headtrack_dynamicOG.py ├── VR_Headtrack_staticOG.py ├── basic_facetrack.py ├── cam_basic.py ├── headtrack.py └── wireframe3.py /README.md: -------------------------------------------------------------------------------- 1 | Head-tracking 2 | ============= 3 | 4 | This project can perform head tracking and change persepective of viewing 3D objects in Python using OpenCV 5 | 6 | [Running these codes requires Python and OpenCV] 7 | 8 | File Descriptions: 9 | 10 | cam_basic.py : Code that displays an image feed from the camera [Python + OpenCV] 11 | 12 | basic_facetrack.py: Code that performs face-tracking using the image feed from a camera [Python + OpenCV] 13 | 14 | headtrack.py: Using face-tracking, it can change perception of a 3D wire frame. Requires wireframe3.py to be in the same directory. The motion is very sudden, however, and needs to be scaled to be controllable. [Python + OpenCV + Pygame] 15 | 16 | VR_Headtrack_dynamicOG.py: Performs headtracking in a rendered 3D environment containing 2 cubes. User can move left/right/up/down. This version uses a dynamic origin setting for motion. [Python + OpenCV + VTK] 17 | 18 | VR_Headtrack_staticOG.py: Performs headtracking in a rendered 3D environment containing 2 cubes. User can move left/right/up/down and even zoom in/out. This version uses a static origin setting. Motion is based on distance of the user's head from the origin. Motion is also scaled. [Python + OpenCV + VTK] 19 | -------------------------------------------------------------------------------- /VR_Headtrack_dynamicOG.py: -------------------------------------------------------------------------------- 1 | 2 | ''' 3 | This python code performs Headtracking in 3D environment - version 1. 4 | Performs movement in up down left right only. 5 | This version implements a dynamic origin setting. Movement based on direction/magnitude of head movement, instead of based on displacement from ORIGIN 6 | Requires Python + OpenCV + VTK''' 7 | 8 | # import vtk python module 9 | 10 | 11 | #!/bin/env python 12 | import vtk 13 | import time 14 | from numpy import * 15 | import cv2 16 | import pygame 17 | 18 | HAAR_CASCADE_PATH = "haarcascade_frontalface_alt.xml" 19 | CAMERA_INDEX = 0 20 | #matrix = [[[0 for x in xrange(4)] for x in xrange(1)] for x in xrange(20)] 21 | matrix1 = [[0 for x in xrange(4)] for x in xrange(1)] 22 | matrix1[0][0] = 0 23 | matrix1[0][1] = 0 24 | matrix1[0][2] = 0 25 | matrix1[0][3] = 0 26 | a = 0 27 | 28 | # create polygonal cube geometry 29 | # here a procedural source object is used, 30 | # a source can also be, e.g., a file reader 31 | cube = vtk.vtkCubeSource() 32 | cube.SetBounds(-1,1,-1,1,-1,1) 33 | cube.SetCenter(0,0,-6) 34 | 35 | # map to graphics library 36 | # a mapper is the interface between the visualization pipeline 37 | # and the graphics model 38 | mapper = vtk.vtkPolyDataMapper() 39 | mapper.SetInput(cube.GetOutput()); # connect source and mapper 40 | 41 | # an actor represent what we see in the scene, 42 | # it coordinates the geometry, its properties, and its transformation 43 | aCube = vtk.vtkActor() 44 | aCube.SetMapper(mapper); 45 | aCube.GetProperty().SetColor(0,1,0); # cube color green 46 | 47 | #cube 2 48 | 49 | cube2 = vtk.vtkCubeSource() 50 | cube2.SetBounds(-0.6,0.6,-0.6,0.6,-0.6,0.6) 51 | cube2.SetCenter(0,0,0) 52 | 53 | # map to graphics library 54 | # a mapper is the interface between the visualization pipeline 55 | # and the graphics model 56 | mapper2 = vtk.vtkPolyDataMapper() 57 | mapper2.SetInput(cube2.GetOutput()); # connect source and mapper 58 | 59 | # an actor represent what we see in the scene, 60 | # it coordinates the geometry, its properties, and its transformation 61 | bCube = vtk.vtkActor() 62 | bCube.SetMapper(mapper2); 63 | bCube.GetProperty().SetColor(0,1,1); # cube color 64 | 65 | # a renderer and render window 66 | ren1 = vtk.vtkRenderer() 67 | renWin = vtk.vtkRenderWindow() 68 | renWin.AddRenderer(ren1); 69 | 70 | # an interactor 71 | #iren = vtk.vtkRenderWindowInteractor() 72 | #iren.SetRenderWindow(renWin); 73 | 74 | # add the actor to the scene 75 | ren1.AddActor(aCube); 76 | ren1.AddActor(bCube); 77 | ren1.SetBackground(1,1,1); # Background color white 78 | i=0 79 | 80 | ## ----------- MORE CAMERA SETTINGS ----------------- 81 | ## Initialize camera 82 | cam = ren1.GetActiveCamera() 83 | cam.SetFocalPoint(1,0,0) 84 | cam.SetViewUp(0.,1.,0.); 85 | 86 | ## This is added so that it gives time to set 87 | ## no border in the OpenGL window and other stuff 88 | ## like minimizing other windows. 89 | 90 | renWin.Render() 91 | t = 0.0 92 | i = 0 93 | j=0 94 | 95 | 96 | 97 | def detect_faces(image): 98 | faces = [] 99 | detected = cascade.detectMultiScale(image,1.3,4,cv2.cv.CV_HAAR_SCALE_IMAGE,(20,20)) 100 | 101 | if detected!=[]: 102 | for (x,y,w,h) in detected: #for (x,y,w,h),n in detected: 103 | faces.append((x,y,w,h)) 104 | return faces 105 | 106 | 107 | def get_motion(f_x,f_y,f_wid): 108 | #yaw is x-axis - horizontal axis 109 | #pitch is y-axis - depth axis 110 | #roll is z-axis - vertical axis 111 | 112 | #[0][0] - x, [0][1] - y, [0][2] - w, [0][3] - h 113 | 114 | #w,h are approx constant for U,D,L,R events 115 | #checking if w,h in range of origin(w,h)+/-5 116 | if (f_wid>(o_wid-20)) and (f_wid<(o_wid+20)): 117 | 118 | #check x while y is same 119 | 120 | 121 | if f_y>(o_y-5) and f_y<(o_y+5): 122 | if f_x>(o_x-5) and f_x<(o_x+5): 123 | #user is in origin location 124 | print 'origin' 125 | return 25 #no motion 126 | else: 127 | if (f_x-o_x)>0: 128 | #LEFT motion event - S button 129 | print 'LEFT', a 130 | return 0 131 | elif (f_x-o_x)<0: 132 | #RIGHT motion event - A button 133 | print 'RIGHT', f_x-o_x 134 | return 1 135 | else: 136 | #check y while x is same 137 | if (f_y-o_y)>0: 138 | #DOWN motion event - Q button 139 | print 'DOWN' 140 | return 2 141 | elif (f_y-o_y)<0: 142 | #UP motion event - W button 143 | print 'UP' 144 | return 3 145 | else: 146 | #possible events: Zoom in, Zoom out 147 | if (f_wid-o_wid)>0: 148 | #ZOOM IN motion event - = button 149 | print 'ZOOM IN' 150 | return 4 151 | elif (f_wid-o_wid)<0: 152 | #ZOOM OUT motion event - -button 153 | print 'ZOOM OUT' 154 | return 5 155 | 156 | ''' 157 | while 1: 158 | renWin.Render(); 159 | if i in range(0,10): 160 | camera=vtk.vtkCamera(); 161 | camera.SetPosition(i, 0,100); 162 | camera.SetFocalPoint(255, 255, 0); 163 | ren1.SetActiveCamera(camera); 164 | #ren1.ResetCameraClippingRange() 165 | 166 | time.sleep(1); 167 | 168 | # begin mouse interaction 169 | #iren.Start(); 170 | ''' 171 | cam.SetPosition(5,5,5) 172 | #time.sleep(0.1) 173 | cam.SetFocalPoint(0,0,0) 174 | if __name__ == '__main__': 175 | 176 | 177 | 178 | cv2.namedWindow("Video",400) 179 | 180 | capture = cv2.VideoCapture(CAMERA_INDEX) 181 | cascade = cv2.CascadeClassifier(HAAR_CASCADE_PATH) 182 | faces = [] #var that stores face rect coords 183 | origin = [] #var that will store the origin coords 184 | o_x = 0 185 | o_y = 0 186 | o_wid = 0 187 | a = 0 188 | 189 | i = 0 190 | c = -1 191 | ctr = 0 #for counting the no. of detections 192 | t = 0 193 | running = True 194 | while running: 195 | retval, image = capture.read() 196 | 197 | #global i, ctr, origin, faces, t, o_x, o_y, o_wid, a 198 | 199 | # Only run the Detection algorithm every 3 frames to improve performance 200 | 201 | if i%3==0: 202 | faces = detect_faces(image) 203 | print 'current coords',faces 204 | 205 | if i%25==0: 206 | if faces != []: 207 | matrix1[0][0] = faces[0][0] 208 | matrix1[0][1] = faces[0][1] 209 | matrix1[0][2] = faces[0][2] 210 | matrix1[0][3] = faces[0][3] 211 | o_x = (matrix1[0][0] + matrix1[0][2])/2 212 | o_y = (matrix1[0][1] + matrix1[0][3])/2 213 | o_wid = matrix1[0][2] 214 | print 'origin is ',matrix1, o_x, o_y, o_wid 215 | 216 | 217 | 218 | 219 | for (x,y,w,h) in faces: 220 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 255) 221 | 222 | 223 | 224 | if o_x!= 0 and faces!=[]: 225 | f_x = (faces[0][0] + faces[0][2])/2 226 | f_y = (faces[0][1] + faces[0][3])/2 227 | f_wid = faces[0][2] 228 | dir = get_motion(f_x,f_y,f_wid) 229 | if (dir == 0 or dir == 1): 230 | a = (f_x-o_x)/float(10) 231 | round(a) 232 | cam.Azimuth(-a) 233 | elif (dir == 2 or dir == 3): 234 | a = (f_y-o_y)/float(10) 235 | round(a) 236 | cam.Elevation(-a) 237 | elif (dir == 4 or dir == 5): 238 | a = (f_wid-o_wid)/float(80) 239 | round(a) 240 | #cam.Zoom(a) 241 | else: 242 | print 'nothing.' 243 | a=0 244 | print 'direction vector',dir 245 | #if dir in key_to_function: 246 | #key_to_function[dir](self) 247 | print 'value:', a 248 | ## -------- THE MAIN FRAME LOOP ---------------------- 249 | # Loop while: rotating the camera and modify 250 | # node coordinates 251 | 252 | 253 | 254 | ## This recomputes the clipping plane. 255 | ## Otherwise, since the camera 256 | ## is rotating, some objects may disappear 257 | ren1.ResetCameraClippingRange() 258 | 259 | 260 | ## Update camera 261 | 262 | 263 | 264 | #cam.Roll(i) 265 | 266 | #print 'App:', cam.GetViewShear() 267 | #cam.SetViewUp(0.,i,0.); 268 | 269 | 270 | 271 | renWin.Render() 272 | 273 | # render an image (lights and cameras are created automatically) 274 | 275 | 276 | cv2.imshow("Video",image) 277 | i += 1 278 | if i>100: 279 | i=0 280 | c = cv2.waitKey(10) 281 | 282 | if c==27: 283 | break 284 | 285 | -------------------------------------------------------------------------------- /VR_Headtrack_staticOG.py: -------------------------------------------------------------------------------- 1 | # File: cube.py 2 | ''' 3 | This python code performs Headtracking in 3D environment - version 2. 4 | Performs movement in up/down/left/righ/zoom in/zoom out. 5 | This version uses a distance algorithm. Motion is based on the displacement from the ORIGIN. 6 | Requires Python + OpenCV + VTK''' 7 | 8 | # import vtk python module 9 | #headtracking code that performs 3D transformations of a cube using head movement 10 | #uses facetrack.py + displayWireframe3.py 11 | 12 | #!/bin/env python 13 | import vtk 14 | import time 15 | from numpy import * 16 | import cv2 17 | import pygame 18 | 19 | HAAR_CASCADE_PATH = "haarcascade_frontalface_alt.xml" 20 | CAMERA_INDEX = 0 21 | matrix = [[[0 for x in xrange(4)] for x in xrange(1)] for x in xrange(20)] 22 | matrix1 = [[[0 for x in xrange(4)] for x in xrange(1)] for x in xrange(1)] 23 | matrix1[0][0][0] = 0 24 | matrix1[0][0][1] = 0 25 | matrix1[0][0][2] = 0 26 | matrix1[0][0][3] = 0 27 | a = 0 28 | 29 | class MyInteractorStyle(vtk.vtkInteractorStyleTrackballCamera): 30 | 31 | def __init__(self,parent=None): 32 | self.AddObserver("MiddleButtonPressEvent",self.middleButtonPressEvent) 33 | self.AddObserver("MiddleButtonReleaseEvent",self.middleButtonReleaseEvent) 34 | 35 | def middleButtonPressEvent(self,obj,event): 36 | print "Middle Button pressed" 37 | self.OnMiddleButtonDown() 38 | return 39 | 40 | def middleButtonReleaseEvent(self,obj,event): 41 | print "Middle Button released" 42 | self.OnMiddleButtonUp() 43 | return 44 | 45 | # create polygonal cube geometry 46 | # here a procedural source object is used, 47 | # a source can also be, e.g., a file reader 48 | # create polygonal cube geometry 49 | # here a procedural source object is used, 50 | # a source can also be, e.g., a file reader 51 | cube = vtk.vtkCubeSource() 52 | cube.SetBounds(-1,1,-1,1,-1,1) 53 | cube.SetCenter(0,0,-3) 54 | 55 | # map to graphics library 56 | # a mapper is the interface between the visualization pipeline 57 | # and the graphics model 58 | mapper = vtk.vtkPolyDataMapper() 59 | mapper.SetInput(cube.GetOutput()); # connect source and mapper 60 | 61 | # an actor represent what we see in the scene, 62 | # it coordinates the geometry, its properties, and its transformation 63 | aCube = vtk.vtkActor() 64 | aCube.SetMapper(mapper); 65 | aCube.GetProperty().SetColor(0,1,0); # cube color green 66 | 67 | #cube 2 68 | 69 | cube2 = vtk.vtkCubeSource() 70 | cube2.SetBounds(-0.6,0.6,-0.6,0.6,-0.6,0.6) 71 | cube2.SetCenter(0,0,0) 72 | 73 | # map to graphics library 74 | # a mapper is the interface between the visualization pipeline 75 | # and the graphics model 76 | mapper2 = vtk.vtkPolyDataMapper() 77 | mapper2.SetInput(cube2.GetOutput()); # connect source and mapper 78 | 79 | # an actor represent what we see in the scene, 80 | # it coordinates the geometry, its properties, and its transformation 81 | bCube = vtk.vtkActor() 82 | bCube.SetMapper(mapper2); 83 | bCube.GetProperty().SetColor(0,1,1); # cube color 84 | # a renderer and render window 85 | ren1 = vtk.vtkRenderer() 86 | renWin = vtk.vtkRenderWindow() 87 | renWin.AddRenderer(ren1); 88 | 89 | 90 | #interactor = vtk.vtkRenderWindowInteractor() 91 | #interactor.SetInteractorStyle(MyInteractorStyle()) 92 | #interactor.SetRenderWindow(renWin) 93 | #interactor.Initialize() 94 | 95 | # an interactor 96 | #iren = vtk.vtkRenderWindowInteractor() 97 | #iren.SetRenderWindow(renWin); 98 | 99 | # add the actor to the scene 100 | ren1.AddActor(aCube); 101 | ren1.AddActor(bCube); 102 | ren1.SetBackground(1,1,1); # Background color white 103 | i=0 104 | 105 | ## ----------- MORE CAMERA SETTINGS ----------------- 106 | ## Initialize camera 107 | cam = ren1.GetActiveCamera() 108 | cam.SetFocalPoint(1,0,0) 109 | cam.SetViewUp(0.,1.,0.); 110 | 111 | ## This is added so that it gives time to set 112 | ## no border in the OpenGL window and other stuff 113 | ## like minimizing other windows. 114 | 115 | renWin.Render() 116 | t = 0.0 117 | i = 0 118 | j=0 119 | 120 | 121 | 122 | def detect_faces(image): 123 | faces = [] 124 | detected = cascade.detectMultiScale(image,1.3,4,cv2.cv.CV_HAAR_SCALE_IMAGE,(20,20)) 125 | 126 | if detected!=[]: 127 | for (x,y,w,h) in detected: #for (x,y,w,h),n in detected: 128 | faces.append((x,y,w,h)) 129 | return faces 130 | 131 | 132 | def get_motion(f_x,f_y,f_wid): 133 | #yaw is x-axis - horizontal axis 134 | #pitch is y-axis - depth axis 135 | #roll is z-axis - vertical axis 136 | 137 | #[0][0] - x, [0][1] - y, [0][2] - w, [0][3] - h 138 | 139 | #w,h are approx constant for U,D,L,R events 140 | #checking if w,h in range of origin(w,h)+/-5 141 | if (f_wid>(o_wid-20)) and (f_wid<(o_wid+20)): 142 | 143 | #check x while y is same 144 | 145 | 146 | if f_y>(o_y-5) and f_y<(o_y+5): 147 | if f_x>(o_x-5) and f_x<(o_x+5): 148 | #user is in origin location 149 | #print 'origin' 150 | return 25 #no motion 151 | else: 152 | if (f_x-o_x)>0: 153 | #LEFT motion event - S button 154 | #print 'LEFT', a 155 | return 0 156 | elif (f_x-o_x)<0: 157 | #RIGHT motion event - A button 158 | #print 'RIGHT', f_x-o_x 159 | return 1 160 | else: 161 | #check y while x is same 162 | if (f_y-o_y)>0: 163 | #DOWN motion event - Q button 164 | #print 'DOWN' 165 | return 2 166 | elif (f_y-o_y)<0: 167 | #UP motion event - W button 168 | #print 'UP' 169 | return 3 170 | else: 171 | #possible events: Zoom in, Zoom out 172 | if (f_wid-o_wid)>0: 173 | #ZOOM IN motion event - = button 174 | #print 'dir-ZOOM IN' 175 | return 4 176 | elif (f_wid-o_wid)<0: 177 | #ZOOM OUT motion event - -button 178 | #print 'dir-ZOOM OUT' 179 | return 5 180 | 181 | ''' 182 | while 1: 183 | renWin.Render(); 184 | if i in range(0,10): 185 | camera=vtk.vtkCamera(); 186 | camera.SetPosition(i, 0,100); 187 | camera.SetFocalPoint(255, 255, 0); 188 | ren1.SetActiveCamera(camera); 189 | #ren1.ResetCameraClippingRange() 190 | 191 | time.sleep(1); 192 | 193 | # begin mouse interaction 194 | #iren.Start(); 195 | ''' 196 | cam.SetPosition(5,5,5) 197 | #time.sleep(0.1) 198 | cam.SetFocalPoint(0,0,0) 199 | if __name__ == '__main__': 200 | 201 | 202 | 203 | cv2.namedWindow("Video",400) 204 | 205 | capture = cv2.VideoCapture(CAMERA_INDEX) 206 | cascade = cv2.CascadeClassifier(HAAR_CASCADE_PATH) 207 | faces = [] #var that stores face rect coords 208 | origin = [] #var that will store the origin coords 209 | o_x = 0 210 | o_y = 0 211 | o_wid = 0 212 | a = 0 213 | 214 | i = 0 215 | c = -1 216 | ctr = 0 #for counting the no. of detections 217 | t = 0 218 | running = True 219 | 220 | while running: 221 | retval, image = capture.read() 222 | 223 | #global i, ctr, origin, faces, t, o_x, o_y, o_wid, a 224 | 225 | # Only run the Detection algorithm every 3 frames to improve performance 226 | for (x,y,w,h) in matrix1[0]: 227 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 0) 228 | if i%3==0: 229 | faces = detect_faces(image) 230 | #print 'current coords',faces 231 | 232 | if faces != []: 233 | if ctr < 20: 234 | matrix [ctr][0][0] = faces[0][0] 235 | matrix [ctr][0][1] = faces[0][1] 236 | matrix [ctr][0][2] = faces[0][2] 237 | matrix [ctr][0][3] = faces[0][3] 238 | #print 'currentvalue and frame:', matrix [ctr], ctr 239 | ctr += 1 240 | if ctr==20: 241 | #approx 3 secs of config time 242 | for t in xrange(ctr): 243 | matrix1 [0][0][0] = matrix1[0][0][0] + matrix[t][0][0] 244 | matrix1 [0][0][1] = matrix1[0][0][1] + matrix[t][0][1] 245 | matrix1 [0][0][2] = matrix1[0][0][2] + matrix[t][0][2] 246 | matrix1 [0][0][3] = matrix1[0][0][3] + matrix[t][0][3] 247 | matrix1[0][0][0]= matrix1[0][0][0]/20 248 | matrix1[0][0][1]= matrix1[0][0][1]/20 249 | matrix1[0][0][2]= matrix1[0][0][2]/20 250 | matrix1[0][0][3]= matrix1[0][0][3]/20 251 | o_x = (matrix1[0][0][0] + matrix1[0][0][2])/2 252 | o_y = (matrix1[0][0][1] + matrix1[0][0][3])/2 253 | o_wid = matrix1[0][0][2] 254 | #print 'origin is ',matrix1, o_x, o_y, o_wid 255 | ctr += 1 256 | 257 | for (x,y,w,h) in matrix1[0]: 258 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 0) 259 | 260 | for (x,y,w,h) in faces: 261 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 255) 262 | 263 | 264 | 265 | if o_x!= 0 and faces!=[]: 266 | f_x = (faces[0][0] + faces[0][2])/2 267 | f_y = (faces[0][1] + faces[0][3])/2 268 | f_wid = faces[0][2] 269 | dir = get_motion(f_x,f_y,f_wid) 270 | if (dir == 0 or dir == 1): 271 | a = (f_x-o_x)/float(10) 272 | round(a) 273 | cam.Azimuth(-a) 274 | elif (dir == 2 or dir == 3): 275 | a = (f_y-o_y)/float(10) 276 | round(a) 277 | cam.Elevation(-a) 278 | 279 | if (f_wid-o_wid>7.5 or o_wid-f_wid>7.5): 280 | #zoom in or zoom out 281 | #a = f_wid/o_wid 282 | a = 0 283 | if(f_wid-o_wid>7.5): 284 | #zoom in case 285 | a=1.01 286 | #print 'zooming in' 287 | elif(o_wid-f_wid>7.5): 288 | #zoom out case 289 | a=0.99 290 | #print 'zooming out' 291 | cam.Zoom(a) 292 | else: 293 | #print 'nothing.' 294 | a=0 295 | #print 'direction vector',dir 296 | #if dir in key_to_function: 297 | #key_to_function[dir](self) 298 | #print 'value:', a 299 | ## -------- THE MAIN FRAME LOOP ---------------------- 300 | # Loop while: rotating the camera and modify 301 | # node coordinates 302 | 303 | 304 | 305 | ## This recomputes the clipping plane. 306 | ## Otherwise, since the camera 307 | ## is rotating, some objects may disappear 308 | ren1.ResetCameraClippingRange() 309 | 310 | #x,y = interactor.GetEventPosition() 311 | #print 'mouse position:',x,', ',y 312 | #interactor.Enable() 313 | #interactor.Start() 314 | 315 | 316 | ## Update camera 317 | 318 | 319 | 320 | #cam.Roll(i) 321 | 322 | #print 'App:', cam.GetViewShear() 323 | #cam.SetViewUp(0.,i,0.); 324 | 325 | 326 | 327 | renWin.Render() 328 | 329 | # render an image (lights and cameras are created automatically) 330 | 331 | 332 | cv2.imshow("Video",image) 333 | i += 1 334 | if i>100: 335 | i=0 336 | c = cv2.waitKey(10) 337 | 338 | if c==27: 339 | break 340 | 341 | -------------------------------------------------------------------------------- /basic_facetrack.py: -------------------------------------------------------------------------------- 1 | 2 | '''This python code performs face tracking. First, the image feed is recieved from the camera. A facial detection algorithm is applied 3 | once in every 5 frames. On detecting the face, a rectangular frame is drawn around the detected face. 4 | Requires Python + OpenCV''' 5 | import cv2 6 | 7 | HAAR_CASCADE_PATH = "haarcascade_frontalface_alt.xml" 8 | CAMERA_INDEX = 0 9 | 10 | def detect_faces(image): 11 | #print 'detect fn' # 12 | faces = [] 13 | #detected = cv.HaarDetectObjects(image, cascade, storage, 1.2, 2, cv.CV_HAAR_DO_CANNY_PRUNING, (100,100)) 14 | detected = cascade.detectMultiScale(image,1.3,4,cv2.cv.CV_HAAR_SCALE_IMAGE,(20,20)) 15 | print detected 16 | 17 | if detected!=[]: 18 | #print 'face detected' # 19 | for (x,y,w,h) in detected: #for (x,y,w,h),n in detected: 20 | faces.append((x,y,w,h)) 21 | return faces 22 | 23 | if __name__ == "__main__": 24 | #print 'creating window' # 25 | cv2.namedWindow("Video") 26 | 27 | capture = cv2.VideoCapture(CAMERA_INDEX) 28 | #storage = cv.CreateMemStorage() 29 | cascade = cv2.CascadeClassifier(HAAR_CASCADE_PATH) 30 | faces = [] 31 | 32 | i = 0 33 | c = -1 34 | while (c == -1): 35 | retval, image = capture.read() 36 | #print 'acq img frm' # 37 | 38 | # Only run the Detection algorithm every 5 frames to improve performance 39 | if i%5==0: 40 | #print 'calling detect' # 41 | faces = detect_faces(image) 42 | 43 | for (x,y,w,h) in faces: 44 | #print 'drawing rectangle' # 45 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 255) 46 | 47 | #print 'showing img' # 48 | cv2.imshow("Video",image) 49 | #cv.ShowImage("Video", image) 50 | i += 1 51 | c = cv2.waitKey(10) 52 | if(c==27): 53 | #escape 54 | break; -------------------------------------------------------------------------------- /cam_basic.py: -------------------------------------------------------------------------------- 1 | 2 | '''This python code simply gets image feed from the webcam. 3 | Requires Python + OpenCV''' 4 | import cv 5 | 6 | cv.NamedWindow("preview", cv.CV_WINDOW_AUTOSIZE) 7 | capture = cv.CaptureFromCAM(0) 8 | 9 | def repeat(): 10 | 11 | frame = cv.QueryFrame(capture) 12 | cv.ShowImage("preview", frame) 13 | cv.WaitKey(10) 14 | 15 | 16 | while True: 17 | repeat() -------------------------------------------------------------------------------- /headtrack.py: -------------------------------------------------------------------------------- 1 | #headtracking code that performs 3D transformations of a cube using head movement 2 | 3 | 4 | ''''This python code performs headtracking with a 3D wire frame cube. Based on head movement, the object is rotated/scaled. Thus, this code can 5 | rotate left/right/up/down, as well as zoom in/out. 6 | Requires wireframe3.py to be in the same directory. 7 | Requires Python + OpenCV + Pygame''' 8 | 9 | #!/bin/env python 10 | 11 | import cv2 12 | import wireframe3 as wireframe 13 | import pygame 14 | 15 | HAAR_CASCADE_PATH = "haarcascade_frontalface_alt.xml" 16 | CAMERA_INDEX = 0 17 | 18 | key_to_function = { 19 | 0: (lambda x: x.translateAll('x', -10)), 20 | 1: (lambda x: x.translateAll('x', 10)), 21 | 2: (lambda x: x.translateAll('y', 10)), 22 | 3: (lambda x: x.translateAll('y', -10)), 23 | 4: (lambda x: x.scaleAll(1.1)), 24 | 5: (lambda x: x.scaleAll( 0.9)), 25 | 6: (lambda x: x.rotateAll('X', 0.1)), 26 | 7: (lambda x: x.rotateAll('X', -0.1)), 27 | 8: (lambda x: x.rotateAll('Y', 0.1)), 28 | 9: (lambda x: x.rotateAll('Y', -0.1)), 29 | 10: (lambda x: x.rotateAll('Z', 0.1)), 30 | 11: (lambda x: x.rotateAll('Z', -0.1)) } 31 | 32 | def detect_faces(image): 33 | faces = [] 34 | detected = cascade.detectMultiScale(image,1.3,4,cv2.cv.CV_HAAR_SCALE_IMAGE,(20,20)) 35 | 36 | if detected!=[]: 37 | for (x,y,w,h) in detected: #for (x,y,w,h),n in detected: 38 | faces.append((x,y,w,h)) 39 | return faces 40 | 41 | def get_motion(face): 42 | #yaw is x-axis - horizontal axis 43 | #pitch is y-axis - depth axis 44 | #roll is z-axis - vertical axis 45 | 46 | #[0][0] - x, [0][1] - y, [0][2] - w, [0][3] - h 47 | 48 | #w,h are approx constant for U,D,L,R events 49 | #checking if w,h in range of origin(w,h)+/-5 50 | if (face[0][2]>(origin[0][2]-5)) and (face[0][2]<(origin[0][2]+5)) and (face[0][3]>(origin[0][3]-5)) and (face[0][3]<(origin[0][3]+5)): 51 | 52 | #check x while y is same 53 | if face[0][1]>(origin[0][1]-5) and face[0][1]<(origin[0][1]+5): 54 | if face[0][0]>(origin[0][0]-5) and face[0][0]<(origin[0][0]+5): 55 | #user is in origin location 56 | print 'origin' 57 | return 25 #no motion 58 | else: 59 | if (face[0][0]-origin[0][0])>0: 60 | #LEFT motion event - S button 61 | print 'LEFT' 62 | return 9 63 | elif (face[0][0]-origin[0][0])<0: 64 | #RIGHT motion event - A button 65 | print 'RIGHT' 66 | return 8 67 | else: 68 | #check y while x is same 69 | if (face[0][1]-origin[0][1])>0: 70 | #DOWN motion event - Q button 71 | print 'DOWN' 72 | return 6 73 | elif (face[0][1]-origin[0][1])<0: 74 | #UP motion event - W button 75 | print 'UP' 76 | return 7 77 | else: 78 | #possible events: Zoom in, Zoom out 79 | if (face[0][2]-origin[0][2])>0: 80 | #ZOOM IN motion event - = button 81 | print 'ZOOM IN' 82 | return 4 83 | elif (face[0][2]-origin[0][2])<0: 84 | #ZOOM OUT motion event - -button 85 | print 'ZOOM OUT' 86 | return 5 87 | 88 | class ProjectionViewer: 89 | """ Displays 3D objects on a Pygame screen """ 90 | 91 | def __init__(self, width, height): 92 | self.width = width 93 | self.height = height 94 | self.screen = pygame.display.set_mode((width, height)) 95 | pygame.display.set_caption('Wireframe Display') 96 | self.background = (10,10,50) 97 | 98 | self.wireframes = {} 99 | self.displayNodes = True 100 | self.displayEdges = True 101 | self.nodeColour = (255,255,255) 102 | self.edgeColour = (200,200,200) 103 | self.nodeRadius = 4 104 | 105 | def addWireframe(self, name, wireframe): 106 | """ Add a named wireframe object. """ 107 | 108 | self.wireframes[name] = wireframe 109 | 110 | def run(self): 111 | """ Create a pygame screen until it is closed. """ 112 | 113 | running = True 114 | while running: 115 | retval, image = capture.read() 116 | 117 | global i, ctr, origin, faces 118 | 119 | # Only run the Detection algorithm every 3 frames to improve performance 120 | if i%3==0: 121 | faces = detect_faces(image) 122 | print 'current coords',faces 123 | ctr += 1 124 | 125 | for (x,y,w,h) in faces: 126 | cv2.cv.Rectangle(cv2.cv.fromarray(image), (x,y), (x+w,y+h), 255) 127 | 128 | if ctr==20: 129 | #approx 3 secs of config time 130 | origin = faces 131 | print 'origin is ',origin 132 | 133 | if origin!=[] and faces!=[]: 134 | dir = get_motion(faces) 135 | print 'direction vector',dir 136 | if dir in key_to_function: 137 | key_to_function[dir](self) 138 | 139 | cv2.imshow("Video",image) 140 | i += 1 141 | c = cv2.waitKey(10) 142 | 143 | if c==27: 144 | break 145 | 146 | self.display() 147 | pygame.display.flip() 148 | 149 | def display(self): 150 | """ Draw the wireframes on the screen. """ 151 | 152 | self.screen.fill(self.background) 153 | 154 | for wireframe in self.wireframes.values(): 155 | if self.displayEdges: 156 | for edge in wireframe.edges: 157 | pygame.draw.aaline(self.screen, self.edgeColour, (edge.start.x, edge.start.y), (edge.stop.x, edge.stop.y), 1) 158 | 159 | if self.displayNodes: 160 | for node in wireframe.nodes: 161 | pygame.draw.circle(self.screen, self.nodeColour, (int(node.x), int(node.y)), self.nodeRadius, 0) 162 | 163 | def translateAll(self, axis, d): 164 | """ Translate all wireframes along a given axis by d units. """ 165 | 166 | for wireframe in self.wireframes.itervalues(): 167 | wireframe.translate(axis, d) 168 | 169 | def scaleAll(self, scale): 170 | """ Scale all wireframes by a given scale, centred on the centre of the screen. """ 171 | 172 | centre_x = self.width/2 173 | centre_y = self.height/2 174 | 175 | for wireframe in self.wireframes.itervalues(): 176 | wireframe.scale((centre_x, centre_y), scale) 177 | 178 | def rotateAll(self, axis, theta): 179 | """ Rotate all wireframe about their centre, along a given axis by a given angle. """ 180 | 181 | rotateFunction = 'rotate' + axis 182 | 183 | for wireframe in self.wireframes.itervalues(): 184 | centre = wireframe.findCentre() 185 | getattr(wireframe, rotateFunction)(centre, theta) 186 | 187 | if __name__ == '__main__': 188 | pv = ProjectionViewer(640, 480) 189 | 190 | cube = wireframe.Wireframe() 191 | cube.addNodes([(x,y,z) for x in (50,250) for y in (50,250) for z in (50,250)]) 192 | cube.addEdges([(n,n+4) for n in range(0,4)]+[(n,n+1) for n in range(0,8,2)]+[(n,n+2) for n in (0,1,4,5)]) 193 | 194 | cv2.namedWindow("Video",400) 195 | 196 | capture = cv2.VideoCapture(CAMERA_INDEX) 197 | cascade = cv2.CascadeClassifier(HAAR_CASCADE_PATH) 198 | faces = [] #var that stores face rect coords 199 | origin = [] #var that will store the origin coords 200 | 201 | i = 0 202 | c = -1 203 | ctr = 0 #for counting the no. of detections 204 | 205 | pv.addWireframe('cube', cube) 206 | pv.run() -------------------------------------------------------------------------------- /wireframe3.py: -------------------------------------------------------------------------------- 1 | #!/bin/env python 2 | 3 | import math 4 | 5 | class Node: 6 | def __init__(self, coordinates): 7 | self.x = coordinates[0] 8 | self.y = coordinates[1] 9 | self.z = coordinates[2] 10 | 11 | class Edge: 12 | def __init__(self, start, stop): 13 | self.start = start 14 | self.stop = stop 15 | 16 | class Wireframe: 17 | def __init__(self): 18 | self.nodes = [] 19 | self.edges = [] 20 | 21 | def addNodes(self, nodeList): 22 | for node in nodeList: 23 | self.nodes.append(Node(node)) 24 | 25 | def addEdges(self, edgeList): 26 | for (start, stop) in edgeList: 27 | self.edges.append(Edge(self.nodes[start], self.nodes[stop])) 28 | 29 | def outputNodes(self): 30 | print "\n --- Nodes --- " 31 | for i, node in enumerate(self.nodes): 32 | print " %d: (%.2f, %.2f, %.2f)" % (i, node.x, node.y, node.z) 33 | 34 | def outputEdges(self): 35 | print "\n --- Edges --- " 36 | for i, edge in enumerate(self.edges): 37 | print " %d: (%.2f, %.2f, %.2f)" % (i, edge.start.x, edge.start.y, edge.start.z), 38 | print "to (%.2f, %.2f, %.2f)" % (edge.stop.x, edge.stop.y, edge.stop.z) 39 | 40 | def translate(self, axis, d): 41 | """ Add constant 'd' to the coordinate 'axis' of each node of a wireframe """ 42 | 43 | if axis in ['x', 'y', 'z']: 44 | for node in self.nodes: 45 | setattr(node, axis, getattr(node, axis) + d) 46 | 47 | def scale(self, (centre_x, centre_y), scale): 48 | """ Scale the wireframe from the centre of the screen """ 49 | 50 | for node in self.nodes: 51 | node.x = centre_x + scale * (node.x - centre_x) 52 | node.y = centre_y + scale * (node.y - centre_y) 53 | node.z *= scale 54 | 55 | def findCentre(self): 56 | """ Find the centre of the wireframe. """ 57 | 58 | num_nodes = len(self.nodes) 59 | meanX = sum([node.x for node in self.nodes]) / num_nodes 60 | meanY = sum([node.y for node in self.nodes]) / num_nodes 61 | meanZ = sum([node.z for node in self.nodes]) / num_nodes 62 | 63 | return (meanX, meanY, meanZ) 64 | 65 | def rotateX(self, (cx,cy,cz), radians): 66 | for node in self.nodes: 67 | y = node.y - cy 68 | z = node.z - cz 69 | d = math.hypot(y, z) 70 | theta = math.atan2(y, z) + radians 71 | node.z = cz + d * math.cos(theta) 72 | node.y = cy + d * math.sin(theta) 73 | 74 | def rotateY(self, (cx,cy,cz), radians): 75 | for node in self.nodes: 76 | x = node.x - cx 77 | z = node.z - cz 78 | d = math.hypot(x, z) 79 | theta = math.atan2(x, z) + radians 80 | node.z = cz + d * math.cos(theta) 81 | node.x = cx + d * math.sin(theta) 82 | 83 | def rotateZ(self, (cx,cy,cz), radians): 84 | for node in self.nodes: 85 | x = node.x - cx 86 | y = node.y - cy 87 | d = math.hypot(y, x) 88 | theta = math.atan2(y, x) + radians 89 | node.x = cx + d * math.cos(theta) 90 | node.y = cy + d * math.sin(theta) 91 | 92 | if __name__ == "__main__": 93 | cube_nodes = [(x,y,z) for x in (0,1) for y in (0,1) for z in (0,1)] 94 | cube = Wireframe() 95 | cube.addNodes(cube_nodes) 96 | cube.addEdges([(n,n+4) for n in range(0,4)]) 97 | cube.addEdges([(n,n+1) for n in range(0,8,2)]) 98 | cube.addEdges([(n,n+2) for n in (0,1,4,5)]) 99 | 100 | cube.outputNodes() 101 | cube.outputEdges() 102 | --------------------------------------------------------------------------------