134 lines
4.3 KiB
Python
134 lines
4.3 KiB
Python
#!/usr/bin/env python
|
|
# Created by br@re-web.eu, 2015
|
|
|
|
import subprocess
|
|
|
|
cv_enabled = False
|
|
gphoto2cffi_enabled = False
|
|
piggyphoto_enabled = False
|
|
|
|
try:
|
|
import cv2 as cv
|
|
cv_enabled = True
|
|
print('OpenCV available')
|
|
except ImportError:
|
|
pass
|
|
|
|
try:
|
|
import gphoto2cffi as gp
|
|
gpExcept = gp.errors.GPhoto2Error
|
|
gphoto2cffi_enabled = True
|
|
print('Gphoto2cffi available')
|
|
except ImportError:
|
|
pass
|
|
|
|
if not gphoto2cffi_enabled:
|
|
try:
|
|
import piggyphoto as gp
|
|
gpExcept = gp.libgphoto2error
|
|
piggyphoto_enabled = True
|
|
print('Piggyphoto available')
|
|
except ImportError:
|
|
pass
|
|
|
|
class CameraException(Exception):
|
|
"""Custom exception class to handle camera class errors"""
|
|
def __init__(self, message, recoverable=False):
|
|
self.message = message
|
|
self.recoverable = recoverable
|
|
|
|
|
|
class Camera_cv:
|
|
def __init__(self, picture_size):
|
|
if cv_enabled:
|
|
self.cap = cv.VideoCapture(0)
|
|
self.cap.set(3, picture_size[0])
|
|
self.cap.set(4, picture_size[1])
|
|
|
|
def has_preview(self):
|
|
return True
|
|
|
|
def take_preview(self, filename="/tmp/preview.jpg"):
|
|
self.take_picture(filename)
|
|
|
|
def take_picture(self, filename="/tmp/picture.jpg"):
|
|
if cv_enabled:
|
|
r, frame = self.cap.read()
|
|
cv.imwrite(filename, frame)
|
|
return filename
|
|
else:
|
|
raise CameraException("OpenCV not available!")
|
|
|
|
def set_idle(self):
|
|
pass
|
|
|
|
|
|
class Camera_gPhoto:
|
|
"""Camera class providing functionality to take pictures using gPhoto 2"""
|
|
|
|
def __init__(self, picture_size):
|
|
self.picture_size = picture_size
|
|
# Print the capabilities of the connected camera
|
|
try:
|
|
if gphoto2cffi_enabled:
|
|
self.cap = gp.Camera()
|
|
elif piggyphoto_enabled:
|
|
self.cap = gp.camera()
|
|
print(self.cap.abilities)
|
|
else:
|
|
print(self.call_gphoto("-a", "/dev/null"))
|
|
except CameraException as e:
|
|
print('Warning: Listing camera capabilities failed (' + e.message + ')')
|
|
except gpExcept as e:
|
|
print('Warning: Listing camera capabilities failed (' + e.message + ')')
|
|
|
|
def call_gphoto(self, action, filename):
|
|
# Try to run the command
|
|
try:
|
|
cmd = "gphoto2 --force-overwrite --quiet " + action + " --filename " + filename
|
|
output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
|
|
if "ERROR" in output:
|
|
raise subprocess.CalledProcessError(returncode=0, cmd=cmd, output=output)
|
|
except subprocess.CalledProcessError as e:
|
|
if "EOS Capture failed: 2019" in e.output or "Perhaps no focus" in e.output:
|
|
raise CameraException("Can't focus!\nMove a little bit!", True)
|
|
elif "No camera found" in e.output:
|
|
raise CameraException("No (supported) camera detected!", False)
|
|
elif "command not found" in e.output:
|
|
raise CameraException("gPhoto2 not found!", False)
|
|
else:
|
|
raise CameraException("Unknown error!\n" + '\n'.join(e.output.split('\n')[1:3]), False)
|
|
return output
|
|
|
|
def has_preview(self):
|
|
return gphoto2cffi_enabled or piggyphoto_enabled
|
|
|
|
def take_preview(self, filename="/tmp/preview.jpg"):
|
|
if gphoto2cffi_enabled:
|
|
self._save_picture(filename, self.cap.get_preview())
|
|
elif piggyphoto_enabled:
|
|
self.cap.capture_preview(filename)
|
|
else:
|
|
raise CameraException("No preview supported!")
|
|
|
|
def take_picture(self, filename="/tmp/picture.jpg"):
|
|
if gphoto2cffi_enabled:
|
|
self._save_picture(filename, self.cap.capture())
|
|
elif piggyphoto_enabled:
|
|
self.cap.capture_image(filename)
|
|
else:
|
|
self.call_gphoto("--capture-image-and-download", filename)
|
|
return filename
|
|
|
|
def _save_picture(self, filename, data):
|
|
f = open(filename, 'wb')
|
|
f.write(data)
|
|
f.close()
|
|
|
|
def set_idle(self):
|
|
if gphoto2cffi_enabled:
|
|
self.cap._get_config()['actions']['viewfinder'].set(False)
|
|
elif piggyphoto_enabled:
|
|
# This doesn't work...
|
|
self.cap.config.main.actions.viewfinder.value = 0
|