Traktor/myenv/Lib/site-packages/pygame/_camera_opencv.py

209 lines
5.3 KiB
Python
Raw Normal View History

2024-05-26 05:12:46 +02:00
"""pygame.camera backend that uses OpenCV.
Uses the cv2 module opencv for python.
See https://pypi.org/project/opencv-python/ for wheels version.
python3 -m pip install opencv-python --user
"""
import numpy
import cv2
import time
import pygame
def list_cameras():
""" """
index = 0
device_idx = []
failed = 0
# Sometimes there are gaps between the device index.
# We keep trying max_gaps times.
max_gaps = 3
while failed < max_gaps:
vcap = cv2.VideoCapture(index)
if not vcap.read()[0]:
failed += 1
else:
device_idx.append(index)
vcap.release()
index += 1
return device_idx
def list_cameras_darwin():
import subprocess
from xml.etree import ElementTree
# pylint: disable=consider-using-with
flout, _ = subprocess.Popen(
"system_profiler -xml SPCameraDataType",
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
).communicate()
last_text = None
cameras = []
for node in ElementTree.fromstring(flout).iterfind("./array/dict/array/dict/*"):
if last_text == "_name":
cameras.append(node.text)
last_text = node.text
return cameras
class Camera:
def __init__(self, device=0, size=(640, 480), mode="RGB", api_preference=None):
"""
api_preference - cv2.CAP_DSHOW cv2.CAP_V4L2 cv2.CAP_MSMF and others
# See https://docs.opencv.org/3.4/d4/d15/group__videoio__flags__base.html
"""
self._device_index = device
self._size = size
self.api_preference = api_preference
if api_preference is not None:
if sys.platform == "win32":
# seems more compatible on windows?
self.api_preference = cv2.CAP_DSHOW
if mode == "RGB":
self._fmt = cv2.COLOR_BGR2RGB
elif mode == "YUV":
self._fmt = cv2.COLOR_BGR2YUV
elif mode == "HSV":
self._fmt = cv2.COLOR_BGR2HSV
else:
raise ValueError("Not a supported mode")
self._open = False
# all of this could have been done in the constructor, but creating
# the VideoCapture is very time consuming, so it makes more sense in the
# actual start() method
def start(self):
if self._open:
return
self._cam = cv2.VideoCapture(self._device_index, self.api_preference)
if not self._cam.isOpened():
raise ValueError("Could not open camera.")
self._cam.set(cv2.CAP_PROP_FRAME_WIDTH, self._size[0])
self._cam.set(cv2.CAP_PROP_FRAME_HEIGHT, self._size[1])
w = self._cam.get(cv2.CAP_PROP_FRAME_WIDTH)
h = self._cam.get(cv2.CAP_PROP_FRAME_HEIGHT)
self._size = (int(w), int(h))
self._flipx = False
self._flipy = False
self._brightness = 1
self._frametime = 1 / self._cam.get(cv2.CAP_PROP_FPS)
self._last_frame_time = 0
self._open = True
def stop(self):
if self._open:
self._cam.release()
self._cam = None
self._open = False
def _check_open(self):
if not self._open:
raise pygame.error("Camera must be started")
def get_size(self):
self._check_open()
return self._size
def set_controls(self, hflip=None, vflip=None, brightness=None):
self._check_open()
if hflip is not None:
self._flipx = bool(hflip)
if vflip is not None:
self._flipy = bool(vflip)
if brightness is not None:
self._cam.set(cv2.CAP_PROP_BRIGHTNESS, brightness)
return self.get_controls()
def get_controls(self):
self._check_open()
return (self._flipx, self._flipy, self._cam.get(cv2.CAP_PROP_BRIGHTNESS))
def query_image(self):
self._check_open()
current_time = time.time()
if current_time - self._last_frame_time > self._frametime:
return True
return False
def get_image(self, dest_surf=None):
self._check_open()
self._last_frame_time = time.time()
_, image = self._cam.read()
image = cv2.cvtColor(image, self._fmt)
flip_code = None
if self._flipx:
if self._flipy:
flip_code = -1
else:
flip_code = 1
elif self._flipy:
flip_code = 0
if flip_code is not None:
image = cv2.flip(image, flip_code)
image = numpy.fliplr(image)
image = numpy.rot90(image)
surf = pygame.surfarray.make_surface(image)
if dest_surf:
dest_surf.blit(surf, (0, 0))
return dest_surf
return surf
def get_raw(self):
self._check_open()
self._last_frame_time = time.time()
_, image = self._cam.read()
return image.tobytes()
class CameraMac(Camera):
def __init__(self, device=0, size=(640, 480), mode="RGB", api_preference=None):
if isinstance(device, int):
_dev = device
elif isinstance(device, str):
_dev = list_cameras_darwin().index(device)
else:
raise TypeError(
"OpenCV-Mac backend can take device indices or names, ints or strings, not ",
str(type(device)),
)
super().__init__(_dev, size, mode, api_preference)