Files
WallE/control/camera.py

73 lines
2.1 KiB
Python

import configparser
import os.path
from io import BytesIO
from typing import NamedTuple, Optional, Tuple
import cv2
from PIL import Image
class FacePos(NamedTuple):
x: int
y: int
w: int
h: int
FACE_DATA = next(filter(os.path.exists, [
'/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml',
'/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml',
]))
face_cascade = cv2.CascadeClassifier(FACE_DATA)
def get_rotate_value(input_value):
if input_value == '0':
return None
if input_value == '90':
return cv2.ROTATE_90_CLOCKWISE
if input_value == '-90' or input_value == '270':
return cv2.ROTATE_90_COUNTERCLOCKWISE
if input_value == '180':
return cv2.ROTATE_180
raise ValueError(f"Unsupported rotation value {input_value!r}")
class Camera:
capture: cv2.VideoCapture
def __init__(self):
self.capture = cv2.VideoCapture(0)
parser = configparser.ConfigParser()
parser.read('config.ini')
self.config = parser['camera']
self.rotate = get_rotate_value(self.config['rotate'])
self.detect_face = False
self.draw_face = self.config.getboolean('draw_face', fallback=False)
def get_image(self) -> Tuple[Optional[bytes], Optional[FacePos]]:
return_code, image = self.capture.read()
if not return_code:
return None, None
if self.rotate is not None:
image = cv2.rotate(image, self.rotate)
face = None
if self.detect_face:
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(image_gray, 1.3, 5)
face = FacePos(*faces[0])
if self.draw_face:
for (x, y, w, h) in faces:
image = cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
jpg = Image.fromarray(image_rgb)
byte_stream = BytesIO()
jpg.save(byte_stream, 'JPEG')
return bytes(byte_stream.getbuffer()), face