@camera.ui/camera-ui-opencv 0.0.19 → 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -3
- package/requirements.txt +1 -1
- package/src/camera_detector.py +209 -188
- package/src/detector_defaults.py +1 -1
- package/src/main.py +9 -8
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"displayName": "OpenCV",
|
|
3
3
|
"name": "@camera.ui/camera-ui-opencv",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.21",
|
|
5
5
|
"description": "camera.ui opencv plugin",
|
|
6
6
|
"author": "seydx (https://github.com/seydx/camera.ui)",
|
|
7
7
|
"main": "./src/main.py",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"url": "https://github.com/seydx/camera.ui/issues"
|
|
22
22
|
},
|
|
23
23
|
"engines": {
|
|
24
|
-
"camera.ui": ">=0.0.
|
|
24
|
+
"camera.ui": ">=0.0.34-alpha.2",
|
|
25
25
|
"node": ">=20.17.0"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/seydx/camera.ui#readme",
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"camera.ui": {
|
|
40
40
|
"pythonVersion": "3.11",
|
|
41
41
|
"extension": "motionDetection",
|
|
42
|
-
"dependencies": []
|
|
42
|
+
"dependencies": [],
|
|
43
|
+
"options": {
|
|
44
|
+
"extendedMotionDetection": true
|
|
45
|
+
}
|
|
43
46
|
}
|
|
44
47
|
}
|
package/requirements.txt
CHANGED
package/src/camera_detector.py
CHANGED
|
@@ -8,9 +8,9 @@ from camera_ui_python_types import (
|
|
|
8
8
|
CameraDevice,
|
|
9
9
|
CameraStorage,
|
|
10
10
|
Detection,
|
|
11
|
-
LoggerService,
|
|
12
11
|
PluginAPI,
|
|
13
12
|
)
|
|
13
|
+
|
|
14
14
|
from detector_defaults import (
|
|
15
15
|
available_models,
|
|
16
16
|
default_area,
|
|
@@ -26,175 +26,214 @@ from detector_defaults import (
|
|
|
26
26
|
from opencv_utils import get_detections, get_detections_bs, get_detections_fd
|
|
27
27
|
from plugin_typings import CameraStorageValues
|
|
28
28
|
|
|
29
|
-
background_tasks = set[asyncio.Task[Any]]()
|
|
30
|
-
|
|
31
29
|
|
|
32
30
|
class CameraDetector:
|
|
33
|
-
def __init__(self, api: PluginAPI,
|
|
31
|
+
def __init__(self, api: PluginAPI, camera_device: CameraDevice) -> None:
|
|
34
32
|
super().__init__()
|
|
35
33
|
|
|
36
34
|
self.api = api
|
|
37
|
-
self.
|
|
38
|
-
self.
|
|
35
|
+
self.camera_device = camera_device
|
|
36
|
+
self.camera_logger = camera_device.logger
|
|
39
37
|
|
|
40
38
|
self.started = False
|
|
41
39
|
self.closed = False
|
|
42
|
-
self.
|
|
40
|
+
self.restarting = False
|
|
41
|
+
|
|
42
|
+
self.initialized = False
|
|
43
|
+
|
|
43
44
|
self.executor = None
|
|
44
45
|
self.previous_frame: Optional[np.ndarray[Any, Any]] = None
|
|
45
46
|
|
|
46
47
|
self.camera_storage: CameraStorage[CameraStorageValues] = self.__create_camera_storage()
|
|
47
|
-
self.camera.on_connected.subscribe(lambda connected: self.start() if connected else self.close())
|
|
48
48
|
|
|
49
|
-
def
|
|
49
|
+
async def initialize(self) -> None:
|
|
50
|
+
if self.initialized:
|
|
51
|
+
return
|
|
52
|
+
|
|
53
|
+
self.initialized = True
|
|
54
|
+
|
|
55
|
+
async def on_connected(connected: bool) -> None:
|
|
56
|
+
if connected:
|
|
57
|
+
await self.start()
|
|
58
|
+
else:
|
|
59
|
+
self.close()
|
|
60
|
+
|
|
61
|
+
await self.camera_device.on_connected.asubscribe(on_connected)
|
|
62
|
+
|
|
63
|
+
async def start(self) -> None:
|
|
50
64
|
if not self.started:
|
|
51
65
|
self.started = True
|
|
52
66
|
self.closed = False
|
|
53
67
|
|
|
54
68
|
self.executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="OpenCV")
|
|
55
69
|
|
|
56
|
-
self.
|
|
57
|
-
f"Starting motion detection for camera {self.camera.name} ({self.__detector_model()})..."
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
self.frame_generation_task = asyncio.create_task(
|
|
61
|
-
self.__detect(), name=f"MotionDetection-{self.camera.name}"
|
|
62
|
-
)
|
|
70
|
+
self.camera_logger.log(f"Starting motion detection ({self.__detector_model()})...")
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
self.frame_generation_task.add_done_callback(
|
|
66
|
-
lambda _: background_tasks.remove(self.frame_generation_task)
|
|
67
|
-
if self.frame_generation_task in background_tasks
|
|
68
|
-
else None
|
|
69
|
-
)
|
|
72
|
+
await self.__start_detection()
|
|
70
73
|
|
|
71
74
|
def close(self) -> None:
|
|
72
|
-
if
|
|
75
|
+
if not self.closed:
|
|
73
76
|
self.started = False
|
|
74
77
|
self.closed = True
|
|
75
78
|
|
|
76
|
-
self.
|
|
77
|
-
|
|
78
|
-
if self.frame_generation_task is not None:
|
|
79
|
-
self.frame_generation_task.cancel()
|
|
80
|
-
self.frame_generation_task = None
|
|
79
|
+
self.camera_logger.log("Stopping motion detection")
|
|
81
80
|
|
|
82
81
|
if self.executor is not None:
|
|
83
82
|
self.executor.shutdown(wait=False)
|
|
84
83
|
self.executor = None
|
|
85
84
|
|
|
86
|
-
def
|
|
87
|
-
|
|
85
|
+
async def __start_detection(self) -> None:
|
|
86
|
+
try:
|
|
87
|
+
await self.__detect()
|
|
88
|
+
except asyncio.CancelledError:
|
|
89
|
+
pass
|
|
90
|
+
except Exception as error:
|
|
91
|
+
self.camera_logger.error("Error generating frames", error)
|
|
92
|
+
await self.__restart()
|
|
93
|
+
|
|
94
|
+
async def __restart(self) -> None:
|
|
95
|
+
if self.restarting or self.closed:
|
|
96
|
+
return
|
|
88
97
|
|
|
89
|
-
self.
|
|
98
|
+
self.restarting = True
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
100
|
+
self.camera_logger.log("Restarting motion detection in 2s...")
|
|
101
|
+
await asyncio.sleep(2)
|
|
102
|
+
|
|
103
|
+
self.restarting = False
|
|
104
|
+
|
|
105
|
+
if self.camera_device.connected and not self.closed:
|
|
106
|
+
await self.__start_detection()
|
|
93
107
|
|
|
94
108
|
async def __detect(self) -> None:
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
async for frame in self.camera.get_frames():
|
|
100
|
-
if self.closed:
|
|
101
|
-
break
|
|
102
|
-
|
|
103
|
-
frame_image = await frame.to_image({"format": {"to": "gray"}})
|
|
104
|
-
image_array = np.array(frame_image["image"])
|
|
105
|
-
|
|
106
|
-
detector_model = self.__detector_model()
|
|
107
|
-
|
|
108
|
-
if detector_model == "Frame Difference":
|
|
109
|
-
area = self.camera_storage.values["frame_difference"]["area"]
|
|
110
|
-
|
|
111
|
-
if self.previous_frame is None:
|
|
112
|
-
self.previous_frame = image_array
|
|
113
|
-
continue
|
|
114
|
-
|
|
115
|
-
dets = await asyncio.get_event_loop().run_in_executor(
|
|
116
|
-
self.executor,
|
|
117
|
-
get_detections_fd,
|
|
118
|
-
self.previous_frame,
|
|
119
|
-
image_array,
|
|
120
|
-
area,
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
self.previous_frame = image_array
|
|
124
|
-
|
|
125
|
-
elif detector_model == "Background Substraction":
|
|
126
|
-
if backSub is None:
|
|
127
|
-
backSub = cv2.createBackgroundSubtractorMOG2(varThreshold=18, detectShadows=False)
|
|
128
|
-
|
|
129
|
-
threshold = self.camera_storage.values["background_substraction"]["threshold"]
|
|
130
|
-
area = self.camera_storage.values["background_substraction"]["area"]
|
|
131
|
-
learning_rate = self.camera_storage.values["background_substraction"]["learning_rate"]
|
|
132
|
-
|
|
133
|
-
dets = await asyncio.get_event_loop().run_in_executor(
|
|
134
|
-
self.executor,
|
|
135
|
-
get_detections_bs,
|
|
136
|
-
image_array,
|
|
137
|
-
backSub,
|
|
138
|
-
threshold,
|
|
139
|
-
area,
|
|
140
|
-
learning_rate,
|
|
141
|
-
)
|
|
142
|
-
|
|
143
|
-
else: # default
|
|
144
|
-
blur = self.camera_storage.values["default"]["blur"]
|
|
145
|
-
threshold = self.camera_storage.values["default"]["threshold"]
|
|
146
|
-
area = self.camera_storage.values["default"]["area"]
|
|
147
|
-
image_array = cv2.stackBlur(image_array, (blur, blur))
|
|
148
|
-
|
|
149
|
-
if self.previous_frame is None:
|
|
150
|
-
self.previous_frame = image_array
|
|
151
|
-
continue
|
|
152
|
-
|
|
153
|
-
dets = await asyncio.get_event_loop().run_in_executor(
|
|
154
|
-
self.executor,
|
|
155
|
-
get_detections,
|
|
156
|
-
self.previous_frame,
|
|
157
|
-
image_array,
|
|
158
|
-
threshold,
|
|
159
|
-
area,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
self.previous_frame = image_array
|
|
163
|
-
|
|
164
|
-
detections: list[Detection] = []
|
|
165
|
-
|
|
166
|
-
for det in dets:
|
|
167
|
-
(x1, y1, x2, y2) = det
|
|
168
|
-
|
|
169
|
-
detection: Detection = {
|
|
170
|
-
"label": "motion",
|
|
171
|
-
"confidence": 1,
|
|
172
|
-
"boundingBox": (x1, y1, x2, y2),
|
|
173
|
-
"inputWidth": frame_image["info"]["width"],
|
|
174
|
-
"inputHeight": frame_image["info"]["height"],
|
|
175
|
-
"origWidth": frame.metadata["origWidth"],
|
|
176
|
-
"origHeight": frame.metadata["origHeight"],
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
detections.append(detection)
|
|
180
|
-
|
|
181
|
-
await self.camera.update_state("motion", {"detections": detections}, frame)
|
|
182
|
-
except asyncio.CancelledError:
|
|
109
|
+
backSub: Optional[cv2.BackgroundSubtractorMOG2] = None
|
|
110
|
+
|
|
111
|
+
async for frame in self.camera_device.get_frames():
|
|
112
|
+
if self.closed:
|
|
183
113
|
break
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
114
|
+
|
|
115
|
+
frame_image = await frame.to_image(
|
|
116
|
+
{"format": {"to": "gray"}, "resize": {"width": 640, "height": 0}}
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
image_array = np.array(frame_image["image"])
|
|
120
|
+
|
|
121
|
+
detector_model = self.__detector_model()
|
|
122
|
+
|
|
123
|
+
if detector_model == "Frame Difference":
|
|
124
|
+
area = self.camera_storage.values["frame_difference"]["area"]
|
|
125
|
+
|
|
126
|
+
if self.previous_frame is None:
|
|
127
|
+
self.previous_frame = image_array
|
|
128
|
+
continue
|
|
129
|
+
|
|
130
|
+
dets = await asyncio.get_event_loop().run_in_executor(
|
|
131
|
+
self.executor,
|
|
132
|
+
get_detections_fd,
|
|
133
|
+
self.previous_frame,
|
|
134
|
+
image_array,
|
|
135
|
+
area,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
self.previous_frame = image_array
|
|
139
|
+
|
|
140
|
+
elif detector_model == "Background Substraction":
|
|
141
|
+
if backSub is None:
|
|
142
|
+
backSub = cv2.createBackgroundSubtractorMOG2(varThreshold=18, detectShadows=False)
|
|
143
|
+
|
|
144
|
+
threshold = self.camera_storage.values["background_substraction"]["threshold"]
|
|
145
|
+
area = self.camera_storage.values["background_substraction"]["area"]
|
|
146
|
+
learning_rate = self.camera_storage.values["background_substraction"]["learning_rate"]
|
|
147
|
+
|
|
148
|
+
dets = await asyncio.get_event_loop().run_in_executor(
|
|
149
|
+
self.executor,
|
|
150
|
+
get_detections_bs,
|
|
151
|
+
image_array,
|
|
152
|
+
backSub,
|
|
153
|
+
threshold,
|
|
154
|
+
area,
|
|
155
|
+
learning_rate,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
else: # default
|
|
159
|
+
blur = self.camera_storage.values["default"]["blur"]
|
|
160
|
+
threshold = self.camera_storage.values["default"]["threshold"]
|
|
161
|
+
area = self.camera_storage.values["default"]["area"]
|
|
162
|
+
image_array = cv2.stackBlur(image_array, (blur, blur))
|
|
163
|
+
|
|
164
|
+
if self.previous_frame is None:
|
|
165
|
+
self.previous_frame = image_array
|
|
166
|
+
continue
|
|
167
|
+
|
|
168
|
+
dets = await asyncio.get_event_loop().run_in_executor(
|
|
169
|
+
self.executor,
|
|
170
|
+
get_detections,
|
|
171
|
+
self.previous_frame,
|
|
172
|
+
image_array,
|
|
173
|
+
threshold,
|
|
174
|
+
area,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
self.previous_frame = image_array
|
|
178
|
+
|
|
179
|
+
detections: list[Detection] = []
|
|
180
|
+
|
|
181
|
+
for det in dets:
|
|
182
|
+
(x1, y1, x2, y2) = det
|
|
183
|
+
|
|
184
|
+
detection: Detection = {
|
|
185
|
+
"label": "motion",
|
|
186
|
+
"confidence": 1,
|
|
187
|
+
"boundingBox": (x1, y1, x2, y2),
|
|
188
|
+
"inputWidth": frame_image["info"]["width"],
|
|
189
|
+
"inputHeight": frame_image["info"]["height"],
|
|
190
|
+
"origWidth": frame.metadata["origWidth"],
|
|
191
|
+
"origHeight": frame.metadata["origHeight"],
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
detections.append(detection)
|
|
195
|
+
|
|
196
|
+
await self.camera_device.update_state("motion", {"detections": detections}, frame)
|
|
189
197
|
|
|
190
198
|
def __detector_model(self) -> Literal["Frame Difference", "Background Substraction", "Default"]:
|
|
191
199
|
return self.camera_storage.values["motion_detector"]
|
|
192
200
|
|
|
201
|
+
async def __default_settings(self) -> None:
|
|
202
|
+
if self.camera_storage.values["motion_detector"] != default_model:
|
|
203
|
+
await self.camera_storage.setValue("motion_detector", default_model)
|
|
204
|
+
|
|
205
|
+
async def __default_d_settings(self) -> None:
|
|
206
|
+
if self.camera_storage.values["default"]["area"] != default_area:
|
|
207
|
+
await self.camera_storage.setValue("default.area", default_area)
|
|
208
|
+
|
|
209
|
+
if self.camera_storage.values["default"]["threshold"] != default_threshold:
|
|
210
|
+
await self.camera_storage.setValue("default.threshold", default_threshold)
|
|
211
|
+
|
|
212
|
+
if self.camera_storage.values["default"]["blur"] != default_blur:
|
|
213
|
+
await self.camera_storage.setValue("default.blur", default_blur)
|
|
214
|
+
|
|
215
|
+
if self.camera_storage.values["default"]["dilation"] != default_dilt:
|
|
216
|
+
await self.camera_storage.setValue("default.dilation", default_dilt)
|
|
217
|
+
|
|
218
|
+
async def __default_bs_settings(self) -> None:
|
|
219
|
+
if self.camera_storage.values["background_substraction"]["area"] != default_area_bs:
|
|
220
|
+
await self.camera_storage.setValue("background_substraction.area", default_area_bs)
|
|
221
|
+
|
|
222
|
+
if self.camera_storage.values["background_substraction"]["threshold"] != default_threshold_bs:
|
|
223
|
+
await self.camera_storage.setValue("background_substraction.threshold", default_threshold_bs)
|
|
224
|
+
|
|
225
|
+
if self.camera_storage.values["background_substraction"]["learning_rate"] != default_learning_rate:
|
|
226
|
+
await self.camera_storage.setValue("background_substraction.learning_rate", default_learning_rate)
|
|
227
|
+
|
|
228
|
+
async def __default_fd_settings(self) -> None:
|
|
229
|
+
if self.camera_storage.values["frame_difference"]["area"] != default_area_fd:
|
|
230
|
+
await self.camera_storage.setValue("frame_difference.area", default_area_fd)
|
|
231
|
+
|
|
193
232
|
def __create_camera_storage(self) -> CameraStorage[CameraStorageValues]:
|
|
194
233
|
camera_storage: CameraStorage[CameraStorageValues] = (
|
|
195
234
|
self.api.storage_controller.create_camera_storage(
|
|
196
235
|
self,
|
|
197
|
-
self.
|
|
236
|
+
self.camera_device.id,
|
|
198
237
|
{
|
|
199
238
|
"motion_detector": {
|
|
200
239
|
"type": "string",
|
|
@@ -206,7 +245,9 @@ class CameraDetector:
|
|
|
206
245
|
"store": True,
|
|
207
246
|
"defaultValue": default_model,
|
|
208
247
|
"required": True,
|
|
209
|
-
"onSet": self.
|
|
248
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
249
|
+
f"Motion detection model changed from {old} to {new}"
|
|
250
|
+
),
|
|
210
251
|
},
|
|
211
252
|
"default": {
|
|
212
253
|
"type": "object",
|
|
@@ -215,7 +256,6 @@ class CameraDetector:
|
|
|
215
256
|
"description": "Settings for the default model",
|
|
216
257
|
"group": "Default",
|
|
217
258
|
"opened": True,
|
|
218
|
-
"hidden": True,
|
|
219
259
|
"properties": {
|
|
220
260
|
"area": {
|
|
221
261
|
"type": "number",
|
|
@@ -228,8 +268,8 @@ class CameraDetector:
|
|
|
228
268
|
"maximum": 1000,
|
|
229
269
|
"step": 1,
|
|
230
270
|
"required": True,
|
|
231
|
-
"onSet": lambda
|
|
232
|
-
|
|
271
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
272
|
+
f"Default model motion area changed from {old} to {new}",
|
|
233
273
|
),
|
|
234
274
|
},
|
|
235
275
|
"threshold": {
|
|
@@ -243,8 +283,8 @@ class CameraDetector:
|
|
|
243
283
|
"maximum": 255,
|
|
244
284
|
"step": 1,
|
|
245
285
|
"required": True,
|
|
246
|
-
"onSet": lambda
|
|
247
|
-
|
|
286
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
287
|
+
f"Default model threshold changed from {old} to {new}",
|
|
248
288
|
),
|
|
249
289
|
},
|
|
250
290
|
"blur": {
|
|
@@ -258,8 +298,8 @@ class CameraDetector:
|
|
|
258
298
|
"maximum": 21,
|
|
259
299
|
"step": 1,
|
|
260
300
|
"required": True,
|
|
261
|
-
"onSet": lambda
|
|
262
|
-
|
|
301
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
302
|
+
f"Default model blur radius changed from {old} to {new}",
|
|
263
303
|
),
|
|
264
304
|
},
|
|
265
305
|
"dilation": {
|
|
@@ -273,11 +313,17 @@ class CameraDetector:
|
|
|
273
313
|
"maximum": 21,
|
|
274
314
|
"step": 1,
|
|
275
315
|
"required": True,
|
|
276
|
-
"onSet": lambda
|
|
277
|
-
self.camera.name,
|
|
316
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
278
317
|
f"Default model dilation size changed from {old} to {new}",
|
|
279
318
|
),
|
|
280
319
|
},
|
|
320
|
+
"reset": {
|
|
321
|
+
"type": "button",
|
|
322
|
+
"title": "Default Settings",
|
|
323
|
+
"key": "default_d",
|
|
324
|
+
"description": "Reset motion detection settings to default",
|
|
325
|
+
"onSet": lambda new, old: self.__default_d_settings(),
|
|
326
|
+
},
|
|
281
327
|
},
|
|
282
328
|
},
|
|
283
329
|
"background_substraction": {
|
|
@@ -287,7 +333,6 @@ class CameraDetector:
|
|
|
287
333
|
"description": "Settings for the background substraction model",
|
|
288
334
|
"group": "Background Substraction",
|
|
289
335
|
"opened": True,
|
|
290
|
-
"hidden": True,
|
|
291
336
|
"properties": {
|
|
292
337
|
"area": {
|
|
293
338
|
"type": "number",
|
|
@@ -300,8 +345,7 @@ class CameraDetector:
|
|
|
300
345
|
"maximum": 1000,
|
|
301
346
|
"step": 1,
|
|
302
347
|
"required": True,
|
|
303
|
-
"onSet": lambda
|
|
304
|
-
self.camera.name,
|
|
348
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
305
349
|
f"Background substraction model area changed from {old} to {new}",
|
|
306
350
|
),
|
|
307
351
|
},
|
|
@@ -316,8 +360,7 @@ class CameraDetector:
|
|
|
316
360
|
"maximum": 255,
|
|
317
361
|
"step": 1,
|
|
318
362
|
"required": True,
|
|
319
|
-
"onSet": lambda
|
|
320
|
-
self.camera.name,
|
|
363
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
321
364
|
f"Background substraction model threshold changed from {old} to {new}",
|
|
322
365
|
),
|
|
323
366
|
},
|
|
@@ -332,11 +375,17 @@ class CameraDetector:
|
|
|
332
375
|
"maximum": 1,
|
|
333
376
|
"step": 0.01,
|
|
334
377
|
"required": True,
|
|
335
|
-
"onSet": lambda
|
|
336
|
-
self.camera.name,
|
|
378
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
337
379
|
f"Background substraction model threshold changed from {old} to {new}",
|
|
338
380
|
),
|
|
339
381
|
},
|
|
382
|
+
"reset": {
|
|
383
|
+
"type": "button",
|
|
384
|
+
"title": "Default Settings",
|
|
385
|
+
"key": "default_bs",
|
|
386
|
+
"description": "Reset motion detection settings to default",
|
|
387
|
+
"onSet": lambda new, old: self.__default_bs_settings(),
|
|
388
|
+
},
|
|
340
389
|
},
|
|
341
390
|
},
|
|
342
391
|
"frame_difference": {
|
|
@@ -346,7 +395,6 @@ class CameraDetector:
|
|
|
346
395
|
"description": "Settings for the frame difference model",
|
|
347
396
|
"group": "Frame Difference",
|
|
348
397
|
"opened": True,
|
|
349
|
-
"hidden": True,
|
|
350
398
|
"properties": {
|
|
351
399
|
"area": {
|
|
352
400
|
"type": "number",
|
|
@@ -359,55 +407,28 @@ class CameraDetector:
|
|
|
359
407
|
"maximum": 1000,
|
|
360
408
|
"step": 1,
|
|
361
409
|
"required": True,
|
|
362
|
-
"onSet": lambda
|
|
363
|
-
self.camera.name,
|
|
410
|
+
"onSet": lambda new, old: self.camera_logger.log(
|
|
364
411
|
f"Frame difference model area changed from {old} to {new}",
|
|
365
412
|
),
|
|
366
|
-
}
|
|
413
|
+
},
|
|
414
|
+
"reset": {
|
|
415
|
+
"type": "button",
|
|
416
|
+
"title": "Default Settings",
|
|
417
|
+
"key": "default_fd",
|
|
418
|
+
"description": "Reset motion detection settings to default",
|
|
419
|
+
"onSet": lambda new, old: self.__default_fd_settings(),
|
|
420
|
+
},
|
|
367
421
|
},
|
|
368
422
|
},
|
|
423
|
+
"reset": {
|
|
424
|
+
"type": "button",
|
|
425
|
+
"title": "Default Settings",
|
|
426
|
+
"key": "default_settings",
|
|
427
|
+
"description": "Reset motion detection settings to default",
|
|
428
|
+
"onSet": lambda new, old: self.__default_settings(),
|
|
429
|
+
},
|
|
369
430
|
},
|
|
370
431
|
)
|
|
371
432
|
)
|
|
372
433
|
|
|
373
|
-
current_model = camera_storage.values["motion_detector"]
|
|
374
|
-
current_model_schema = None
|
|
375
|
-
|
|
376
|
-
if current_model == "Default":
|
|
377
|
-
current_model_schema = camera_storage.getSchema("default")
|
|
378
|
-
elif current_model == "Background Substraction":
|
|
379
|
-
current_model_schema = camera_storage.getSchema("background_substraction")
|
|
380
|
-
elif current_model == "Frame Difference":
|
|
381
|
-
current_model_schema = camera_storage.getSchema("frame_difference")
|
|
382
|
-
|
|
383
|
-
if current_model_schema:
|
|
384
|
-
current_model_schema["hidden"] = False
|
|
385
|
-
|
|
386
434
|
return camera_storage
|
|
387
|
-
|
|
388
|
-
def __change_model(self, old_model: str, new_model: str) -> None:
|
|
389
|
-
self.logger.log(self.camera.name, f"Motion detection model changed from {old_model} to {new_model}")
|
|
390
|
-
|
|
391
|
-
old_schema = None
|
|
392
|
-
new_schema = None
|
|
393
|
-
self.previous_frame = None
|
|
394
|
-
|
|
395
|
-
if old_model == "Default":
|
|
396
|
-
old_schema = self.camera_storage.getSchema("default")
|
|
397
|
-
elif old_model == "Background Substraction":
|
|
398
|
-
old_schema = self.camera_storage.getSchema("background_substraction")
|
|
399
|
-
elif old_model == "Frame Difference":
|
|
400
|
-
old_schema = self.camera_storage.getSchema("frame_difference")
|
|
401
|
-
|
|
402
|
-
if new_model == "Default":
|
|
403
|
-
new_schema = self.camera_storage.getSchema("default")
|
|
404
|
-
elif new_model == "Background Substraction":
|
|
405
|
-
new_schema = self.camera_storage.getSchema("background_substraction")
|
|
406
|
-
elif new_model == "Frame Difference":
|
|
407
|
-
new_schema = self.camera_storage.getSchema("frame_difference")
|
|
408
|
-
|
|
409
|
-
if old_schema:
|
|
410
|
-
old_schema["hidden"] = True
|
|
411
|
-
|
|
412
|
-
if new_schema:
|
|
413
|
-
new_schema["hidden"] = False
|
package/src/detector_defaults.py
CHANGED
package/src/main.py
CHANGED
|
@@ -5,7 +5,6 @@ from typing import Any, Optional, Union
|
|
|
5
5
|
|
|
6
6
|
import cv2
|
|
7
7
|
import numpy as np
|
|
8
|
-
from camera_detector import CameraDetector
|
|
9
8
|
from camera_ui_python_types import (
|
|
10
9
|
CameraDevice,
|
|
11
10
|
CameraExtension,
|
|
@@ -16,6 +15,8 @@ from camera_ui_python_types import (
|
|
|
16
15
|
PluginAPI,
|
|
17
16
|
RootSchema,
|
|
18
17
|
)
|
|
18
|
+
|
|
19
|
+
from camera_detector import CameraDetector
|
|
19
20
|
from detector_defaults import (
|
|
20
21
|
default_area,
|
|
21
22
|
default_area_bs,
|
|
@@ -46,7 +47,7 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
46
47
|
async def camera_selected(self, camera: CameraDevice, extension: CameraExtension) -> None:
|
|
47
48
|
self.logger.log(f"New camera added ({extension}): {camera.name}")
|
|
48
49
|
self.cameras[camera.id] = camera
|
|
49
|
-
self.create_detector(camera)
|
|
50
|
+
await self.create_detector(camera)
|
|
50
51
|
|
|
51
52
|
def camera_deselected(self, id: str, extension: CameraExtension) -> None:
|
|
52
53
|
camera = self.cameras.get(id)
|
|
@@ -56,11 +57,10 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
56
57
|
self.remove_detector(self.cameras[id])
|
|
57
58
|
del self.cameras[id]
|
|
58
59
|
|
|
59
|
-
def start(self) -> None:
|
|
60
|
+
async def start(self) -> None:
|
|
60
61
|
self.logger.log("Plugin Started")
|
|
61
62
|
|
|
62
|
-
for
|
|
63
|
-
self.create_detector(camera_device)
|
|
63
|
+
await asyncio.gather(*[self.create_detector(camera) for camera in self.cameras.values()])
|
|
64
64
|
|
|
65
65
|
def stop(self) -> None:
|
|
66
66
|
self.logger.log("Plugin Stopped")
|
|
@@ -68,7 +68,7 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
68
68
|
detectors_copy = list(self.detectors.values())
|
|
69
69
|
|
|
70
70
|
for detector in detectors_copy:
|
|
71
|
-
self.remove_detector(detector.
|
|
71
|
+
self.remove_detector(detector.camera_device)
|
|
72
72
|
|
|
73
73
|
async def onFormSubmit(self, action_id: str, payload: Any) -> Union[FormSubmitResponse, None]:
|
|
74
74
|
print("Form submitted", action_id, payload)
|
|
@@ -77,9 +77,10 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
77
77
|
for camera in cameras:
|
|
78
78
|
self.cameras[camera.id] = camera
|
|
79
79
|
|
|
80
|
-
def create_detector(self, camera: CameraDevice) -> None:
|
|
81
|
-
detector = CameraDetector(self.api, camera
|
|
80
|
+
async def create_detector(self, camera: CameraDevice) -> None:
|
|
81
|
+
detector = CameraDetector(self.api, camera)
|
|
82
82
|
self.detectors[camera.id] = detector
|
|
83
|
+
await detector.initialize()
|
|
83
84
|
|
|
84
85
|
def remove_detector(self, camera: CameraDevice) -> None:
|
|
85
86
|
detector = self.detectors[camera.id]
|