feat: start of smart head movement
This commit is contained in:
@@ -13,7 +13,7 @@ camera = Camera()
|
|||||||
|
|
||||||
def camera_image():
|
def camera_image():
|
||||||
scheduler.enter(INTERVAL_IMAGE, 1, camera_image)
|
scheduler.enter(INTERVAL_IMAGE, 1, camera_image)
|
||||||
image = camera.get_image()
|
image, face = camera.get_image()
|
||||||
redisdb.publish('image', image)
|
redisdb.publish('image', image)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
[camera]
|
[camera]
|
||||||
rotate=0
|
rotate=0
|
||||||
|
draw_face=true
|
||||||
@@ -1,11 +1,19 @@
|
|||||||
from io import BytesIO
|
|
||||||
import os.path
|
|
||||||
from typing import Optional
|
|
||||||
import configparser
|
import configparser
|
||||||
|
import os.path
|
||||||
|
from io import BytesIO
|
||||||
|
from typing import NamedTuple, Optional, Tuple
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
class FacePos(NamedTuple):
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
w: int
|
||||||
|
h: int
|
||||||
|
|
||||||
|
|
||||||
FACE_DATA = next(filter(os.path.exists, [
|
FACE_DATA = next(filter(os.path.exists, [
|
||||||
'/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml',
|
'/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml',
|
||||||
'/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml',
|
'/usr/share/opencv4/haarcascades/haarcascade_frontalface_default.xml',
|
||||||
@@ -38,20 +46,27 @@ class Camera:
|
|||||||
|
|
||||||
self.rotate = get_rotate_value(self.config['rotate'])
|
self.rotate = get_rotate_value(self.config['rotate'])
|
||||||
|
|
||||||
def get_image(self) -> Optional[bytes]:
|
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()
|
return_code, image = self.capture.read()
|
||||||
if not return_code:
|
if not return_code:
|
||||||
return None
|
return None, None
|
||||||
if self.rotate is not None:
|
if self.rotate is not None:
|
||||||
image = cv2.rotate(image, self.rotate)
|
image = cv2.rotate(image, self.rotate)
|
||||||
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
|
||||||
|
|
||||||
|
face = None
|
||||||
|
if self.detect_face:
|
||||||
|
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
faces = face_cascade.detectMultiScale(image_gray, 1.3, 5)
|
faces = face_cascade.detectMultiScale(image_gray, 1.3, 5)
|
||||||
|
face = FacePos(*faces[0])
|
||||||
|
if self.draw_face:
|
||||||
for (x, y, w, h) in faces:
|
for (x, y, w, h) in faces:
|
||||||
image = cv2.rectangle(image, (x, y), (x+w, y+h), (255, 0, 0), 2)
|
image = cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
|
||||||
|
|
||||||
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
|
||||||
jpg = Image.fromarray(image_rgb)
|
jpg = Image.fromarray(image_rgb)
|
||||||
byte_stream = BytesIO()
|
byte_stream = BytesIO()
|
||||||
jpg.save(byte_stream, 'JPEG')
|
jpg.save(byte_stream, 'JPEG')
|
||||||
return bytes(byte_stream.getbuffer())
|
return bytes(byte_stream.getbuffer()), face
|
||||||
|
|||||||
Reference in New Issue
Block a user