-
Notifications
You must be signed in to change notification settings - Fork 0
/
lights.py
executable file
·135 lines (112 loc) · 4.2 KB
/
lights.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env -S poetry run python
from functools import lru_cache
import random
import time
import os
import random
import cv2
from framegrab import FrameGrabber, MotionDetector
from groundlight import Groundlight
from imgcat import imgcat
import DMXEnttecPro
import numpy as np
from PIL import Image
import typer
from simple_tts import make_mp3_text, play_mp3
cli_app = typer.Typer(no_args_is_help=True, context_settings={"help_option_names": ["-h", "--help"]})
class VisualHalloween():
def __init__(self, query_name:str, query_text:str, scream_callback:callable=None, messages:list[str]=None, soundfile_dir:str=""):
self.gl = Groundlight()
self.name = query_name
self.detector = self.gl.get_or_create_detector(
name=query_name,
query=query_text,
)
print(f"Using detector {self.detector}")
self.scream_callback = scream_callback
if not messages:
self.tts_choices = ["Oh no!"]
else:
self.tts_choices = messages
self.soundfile_dir = soundfile_dir
def tts_scream(self):
text_choices = self.tts_choices
chosen_text = random.choice(text_choices)
print(f"\n\n\nSCREAMING!!! {chosen_text}\n\n\n")
audiofile = make_mp3_text(chosen_text)
play_mp3(audiofile)
def pick_and_play_soundfile(self, soundfile_dir:str):
soundfiles = os.listdir(soundfile_dir)
soundfile = soundfile_dir + "/" + random.choice(soundfiles)
print(f"Playing {soundfile}")
play_mp3(soundfile)
def do_scream(self):
if self.scream_callback:
self.scream_callback()
elif self.soundfile_dir:
self.pick_and_play_soundfile(self.soundfile_dir)
else:
self.tts_scream()
def process_image(self, frame: np.ndarray) -> bool:
start_time = time.monotonic()
iq = self.gl.ask_ml(self.detector, frame)
elased = time.monotonic() - start_time
print(f"Got {iq.result} for {self.name} after {elased:.2f}s on image of size {frame.shape} with {iq.id}")
if iq.result.label == "YES":
self.do_scream()
return True
return False
def set_color(dmx, dim, r, g, b, w):
dmx.set_channel(4, dim)
dmx.set_channel(5, r)
dmx.set_channel(6, g)
dmx.set_channel(7, b)
dmx.set_channel(8, w)
dmx.submit()
def mainloop(motdet_pct:float=1.5, motdet_val:int=50):
grabber = FrameGrabber.from_yaml("camera.yaml")[0]
motdet = MotionDetector(motdet_pct, motdet_val)
screamers = [
VisualHalloween("doggie", "Can you see a dog?", soundfile_dir="media/dog"),
VisualHalloween("baby-stroller", "Is there a baby stroller in view?", soundfile_dir="media/baby"),
VisualHalloween("tongue-sticking","Is there a person facing the camera and sticking out their tongue?",
messages=[
"I will rip that tongue right out of you.",
"Hey that's rude!",
"Cut it out, or I'll cut that tongue out of you.",
"Are you trying to make me angry?",
]),
]
dmx = DMXEnttecPro.Controller('/dev/ttyUSB0')
set_color(dmx, 160, 0, 180, 180, 0)
ema_fps = None
last_fps_message = 0
while True:
start_time = time.monotonic()
frame = grabber.grab()
if frame is None:
print("No frame captured!")
continue
# invert the frame by 180 degrees
frame = np.rot90(frame, 2)
motion = motdet.motion_detected(frame)
elapsed = time.monotonic() - start_time
current_fps = 1.0 / elapsed
if ema_fps is None:
ema_fps = current_fps
else:
ema_fps = 0.9 * ema_fps + 0.1 * current_fps
if motion:
# reverse BGR for preview
imgcat(frame[:, :, ::-1])
#TODO: activate lights!
set_color(dmx, 255, 255, 0, 0, 0)
else:
#TODO: turn off lights.
set_color(dmx, 160, 0, 180, 180, 0)
pass
if time.monotonic() - last_fps_message > 1:
last_fps_message = time.monotonic()
print(f"fps={ema_fps:.2f}")
if __name__ == "__main__":
mainloop()