chiark / gitweb /
Do not open the webcam connection permenatly till a webcam feature is used, only...
[cura.git] / Cura / gui / util / webcam.py
1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
3
4 import os
5 import glob
6 import subprocess
7 import platform
8
9 import wx
10
11 from Cura.util import profile
12 from Cura.util.resources import getPathForImage
13
14 try:
15         #Try to find the OpenCV library for video capture.
16         from opencv import cv
17         from opencv import highgui
18 except:
19         cv = None
20
21 try:
22         #Use the vidcap library directly from the VideoCapture package. (Windows only)
23         #       http://videocapture.sourceforge.net/
24         # We're using the binary interface, not the python interface, so we don't depend on PIL
25         import vidcap as win32vidcap
26 except:
27         win32vidcap = None
28
29 def hasWebcamSupport():
30         if cv == None and win32vidcap == None:
31                 return False
32         if not os.path.exists(getFFMPEGpath()):
33                 return False
34         return True
35
36
37 def getFFMPEGpath():
38         if platform.system() == "Windows":
39                 return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../../ffmpeg.exe"))
40         elif os.path.exists('/usr/bin/ffmpeg'):
41                 return '/usr/bin/ffmpeg'
42         return os.path.normpath(os.path.join(os.path.split(__file__)[0], "../../ffmpeg"))
43
44
45 class webcam(object):
46         def __init__(self):
47                 self._cam = None
48                 self._hasCamera = False
49                 self._overlayImage = wx.Bitmap(getPathForImage('cura-overlay.png'))
50                 self._overlayUltimaker = wx.Bitmap(getPathForImage('ultimaker-overlay.png'))
51
52                 #open the camera and close it to check if we have a camera, then open the camera again when we use it for the
53                 # first time.
54                 self._hasCamera = True
55                 self._openCam()
56                 if self._cam is not None:
57                         print "detected camera"
58                         del self._cam
59                         self._cam = None
60                         self._hasCamera = True
61                 else:
62                         self._hasCamera = False
63
64                 self._doTimelapse = False
65                 self._bitmap = None
66
67         def hasCamera(self):
68                 return self._hasCamera
69
70         def _openCam(self):
71                 print "open camera"
72                 if not self._hasCamera:
73                         return False
74                 if self._cam is not None:
75                         return True
76
77                 if cv is not None:
78                         self._cam = highgui.cvCreateCameraCapture(-1)
79                 elif win32vidcap is not None:
80                         try:
81                                 self._cam = win32vidcap.new_Dev(0, False)
82                         except:
83                                 pass
84                 return self._cam is not None
85
86         def propertyPages(self):
87                 if cv is not None:
88                         #TODO Make an OpenCV property page
89                         return []
90                 elif win32vidcap is not None:
91                         return ['Image properties', 'Format properties']
92
93         def openPropertyPage(self, pageType=0):
94                 if not self._openCam():
95                         return
96                 if cv is not None:
97                         pass
98                 elif win32vidcap is not None:
99                         if pageType == 0:
100                                 self._cam.displaycapturefilterproperties()
101                         else:
102                                 del self._cam
103                                 self._cam = None
104                                 tmp = win32vidcap.new_Dev(0, False)
105                                 tmp.displaycapturepinproperties()
106                                 self._cam = tmp
107
108         def takeNewImage(self):
109                 if not self._openCam():
110                         return
111                 if cv is not None:
112                         frame = cv.QueryFrame(self._cam)
113                         cv.CvtColor(frame, frame, cv.CV_BGR2RGB)
114                         bitmap = wx.BitmapFromBuffer(frame.width, frame.height, frame.imageData)
115                 elif win32vidcap is not None:
116                         buffer, width, height = self._cam.getbuffer()
117                         try:
118                                 wxImage = wx.EmptyImage(width, height)
119                                 wxImage.SetData(buffer[::-1])
120                                 if self._bitmap is not None:
121                                         del self._bitmap
122                                 bitmap = wxImage.ConvertToBitmap()
123                                 del wxImage
124                                 del buffer
125                         except:
126                                 pass
127
128                 dc = wx.MemoryDC()
129                 dc.SelectObject(bitmap)
130                 dc.DrawBitmap(self._overlayImage, bitmap.GetWidth() - self._overlayImage.GetWidth() - 5, 5, True)
131                 if profile.getPreference('machine_type') == 'ultimaker':
132                         dc.DrawBitmap(self._overlayUltimaker, (bitmap.GetWidth() - self._overlayUltimaker.GetWidth()) / 2,
133                                 bitmap.GetHeight() - self._overlayUltimaker.GetHeight() - 5, True)
134                 dc.SelectObject(wx.NullBitmap)
135
136                 self._bitmap = bitmap
137
138                 if self._doTimelapse:
139                         filename = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../__tmp_snap",
140                                 "__tmp_snap_%04d.jpg" % (self._snapshotCount)))
141                         self._snapshotCount += 1
142                         bitmap.SaveFile(filename, wx.BITMAP_TYPE_JPEG)
143
144                 return self._bitmap
145
146         def getLastImage(self):
147                 return self._bitmap
148
149         def startTimelapse(self, filename):
150                 if not self._openCam():
151                         return
152                 self._cleanTempDir()
153                 self._timelapseFilename = filename
154                 self._snapshotCount = 0
155                 self._doTimelapse = True
156                 print "startTimelapse"
157
158         def endTimelapse(self):
159                 if self._doTimelapse:
160                         ffmpeg = getFFMPEGpath()
161                         basePath = os.path.normpath(
162                                 os.path.join(os.path.split(__file__)[0], "../__tmp_snap", "__tmp_snap_%04d.jpg"))
163                         subprocess.call(
164                                 [ffmpeg, '-r', '12.5', '-i', basePath, '-vcodec', 'mpeg2video', '-pix_fmt', 'yuv420p', '-r', '25', '-y',
165                                  '-b:v', '1500k', '-f', 'vob', self._timelapseFilename])
166                 self._doTimelapse = False
167
168         def _cleanTempDir(self):
169                 basePath = os.path.normpath(os.path.join(os.path.split(__file__)[0], "../__tmp_snap"))
170                 try:
171                         os.makedirs(basePath)
172                 except:
173                         pass
174                 for filename in glob.iglob(basePath + "/*.jpg"):
175                         os.remove(filename)