@camera.ui/camera-ui-opencv 0.0.8 → 0.0.10
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 +2 -2
- package/requirements.txt +1 -1
- package/src/camera_detector.py +275 -305
- package/src/detector_defaults.py +11 -8
- package/src/main.py +65 -80
- package/src/opencv_utils.py +6 -92
- package/src/plugin_typings.py +3 -2
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.10",
|
|
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.17",
|
|
25
25
|
"node": ">=18.12.0"
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://github.com/seydx/camera.ui#readme",
|
package/requirements.txt
CHANGED
package/src/camera_detector.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
-
import time
|
|
3
2
|
from concurrent.futures import ThreadPoolExecutor
|
|
4
3
|
from typing import Any, Literal, Optional
|
|
5
4
|
|
|
@@ -14,14 +13,15 @@ from camera_ui_python_types import (
|
|
|
14
13
|
)
|
|
15
14
|
from detector_defaults import (
|
|
16
15
|
available_models,
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
default_area,
|
|
17
|
+
default_area_bs,
|
|
18
|
+
default_area_fd,
|
|
19
|
+
default_blur,
|
|
20
|
+
default_dilt,
|
|
21
|
+
default_learning_rate,
|
|
22
|
+
default_model,
|
|
23
|
+
default_threshold,
|
|
24
|
+
default_threshold_bs,
|
|
25
25
|
)
|
|
26
26
|
from opencv_utils import get_detections, get_detections_bs, get_detections_fd
|
|
27
27
|
from plugin_typings import CameraStorageValues
|
|
@@ -41,6 +41,7 @@ class CameraDetector:
|
|
|
41
41
|
self.closed = False
|
|
42
42
|
self.frame_generation_task: Optional[asyncio.Task[Any]] = None
|
|
43
43
|
self.executor = None
|
|
44
|
+
self.previous_frame: Optional[np.ndarray[Any, Any]] = None
|
|
44
45
|
|
|
45
46
|
self.camera_storage: CameraStorage[CameraStorageValues] = self.__create_camera_storage()
|
|
46
47
|
self.camera.on_connected.subscribe(lambda connected: self.start() if connected else self.close())
|
|
@@ -91,314 +92,282 @@ class CameraDetector:
|
|
|
91
92
|
self.start()
|
|
92
93
|
|
|
93
94
|
async def __detect(self) -> None:
|
|
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
|
-
area
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
threshold
|
|
145
|
-
area
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
detections.append(detection)
|
|
191
|
-
|
|
192
|
-
await self.camera.update_state("motion", {"detections": detections}, frame)
|
|
193
|
-
|
|
194
|
-
except asyncio.CancelledError:
|
|
195
|
-
pass
|
|
196
|
-
except Exception as error:
|
|
197
|
-
self.logger.error(self.camera.name, "Error generating frames", error)
|
|
198
|
-
finally:
|
|
199
|
-
if not self.closed:
|
|
200
|
-
self.restart()
|
|
95
|
+
while not self.closed:
|
|
96
|
+
try:
|
|
97
|
+
backSub: Optional[cv2.BackgroundSubtractorMOG2] = None
|
|
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:
|
|
183
|
+
break
|
|
184
|
+
except Exception as error:
|
|
185
|
+
self.logger.error(self.camera.name, "Error generating frames", error)
|
|
186
|
+
self.logger.log(self.camera.name, "Restarting motion detection in 5 seconds...")
|
|
187
|
+
await asyncio.sleep(5)
|
|
188
|
+
continue
|
|
201
189
|
|
|
202
190
|
def __detector_model(self) -> Literal["Frame Difference", "Background Substraction", "Default"]:
|
|
203
191
|
return self.camera_storage.values["motion_detector"]
|
|
204
192
|
|
|
205
193
|
def __create_camera_storage(self) -> CameraStorage[CameraStorageValues]:
|
|
206
|
-
camera_storage:
|
|
207
|
-
self.api.storage_controller.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"group": "Manage",
|
|
223
|
-
"enum": available_models,
|
|
224
|
-
"store": True,
|
|
225
|
-
"defaultValue": "Default",
|
|
226
|
-
"required": True,
|
|
227
|
-
"onSet": self.__change_model,
|
|
228
|
-
},
|
|
229
|
-
"default": {
|
|
230
|
-
"type": "object",
|
|
231
|
-
"key": "default",
|
|
232
|
-
"title": "Default",
|
|
233
|
-
"description": "Settings for the default model",
|
|
234
|
-
"group": "Default",
|
|
235
|
-
"opened": True,
|
|
236
|
-
"hidden": True,
|
|
237
|
-
"properties": {
|
|
238
|
-
"area": {
|
|
239
|
-
"type": "number",
|
|
240
|
-
"key": "area",
|
|
241
|
-
"title": "Area",
|
|
242
|
-
"description": "Minimum area for a motion detection",
|
|
243
|
-
"store": True,
|
|
244
|
-
"defaultValue": defaultArea,
|
|
245
|
-
"minimum": 10,
|
|
246
|
-
"maximum": 1000,
|
|
247
|
-
"step": 1,
|
|
248
|
-
"required": True,
|
|
249
|
-
"onSet": lambda old, new: self.logger.log(
|
|
250
|
-
self.camera.name, f"Default model motion area changed from {old} to {new}"
|
|
251
|
-
),
|
|
252
|
-
},
|
|
253
|
-
"threshold": {
|
|
254
|
-
"type": "number",
|
|
255
|
-
"key": "threshold",
|
|
256
|
-
"title": "Threshold",
|
|
257
|
-
"description": "Threshold for the default model",
|
|
258
|
-
"store": True,
|
|
259
|
-
"defaultValue": defaultThreshold,
|
|
260
|
-
"minimum": 1,
|
|
261
|
-
"maximum": 255,
|
|
262
|
-
"step": 1,
|
|
263
|
-
"required": True,
|
|
264
|
-
"onSet": lambda old, new: self.logger.log(
|
|
265
|
-
self.camera.name, f"Default model threshold changed from {old} to {new}"
|
|
266
|
-
),
|
|
267
|
-
},
|
|
268
|
-
"blur": {
|
|
269
|
-
"type": "number",
|
|
270
|
-
"key": "blur",
|
|
271
|
-
"title": "Blur",
|
|
272
|
-
"description": "Blur for the default model",
|
|
273
|
-
"store": True,
|
|
274
|
-
"defaultValue": defaultBlur,
|
|
275
|
-
"minimum": 1,
|
|
276
|
-
"maximum": 21,
|
|
277
|
-
"step": 1,
|
|
278
|
-
"required": True,
|
|
279
|
-
"onSet": lambda old, new: self.logger.log(
|
|
280
|
-
self.camera.name, f"Default model blur radius changed from {old} to {new}"
|
|
281
|
-
),
|
|
282
|
-
},
|
|
283
|
-
"dilation": {
|
|
284
|
-
"type": "number",
|
|
285
|
-
"key": "dilation",
|
|
286
|
-
"title": "Dilation",
|
|
287
|
-
"description": "Dilation for the default model",
|
|
288
|
-
"store": True,
|
|
289
|
-
"defaultValue": defaultDilt,
|
|
290
|
-
"minimum": 1,
|
|
291
|
-
"maximum": 21,
|
|
292
|
-
"step": 1,
|
|
293
|
-
"required": True,
|
|
294
|
-
"onSet": lambda old, new: self.logger.log(
|
|
295
|
-
self.camera.name, f"Default model dilation size changed from {old} to {new}"
|
|
296
|
-
),
|
|
297
|
-
},
|
|
298
|
-
"reference_frame_frequency": {
|
|
299
|
-
"type": "number",
|
|
300
|
-
"key": "reference_frame_frequency",
|
|
301
|
-
"title": "Reference Frame Frequency",
|
|
302
|
-
"description": "Frequency to update the reference frame",
|
|
303
|
-
"store": True,
|
|
304
|
-
"defaultValue": defaultReferenceFrameFrequency,
|
|
305
|
-
"minimum": 1,
|
|
306
|
-
"maximum": 60,
|
|
307
|
-
"step": 1,
|
|
308
|
-
"required": True,
|
|
309
|
-
"onSet": lambda old, new: self.logger.log(
|
|
310
|
-
self.camera.name,
|
|
311
|
-
f"Default model reference frame frequency changed from {old} to {new}",
|
|
312
|
-
),
|
|
313
|
-
},
|
|
194
|
+
camera_storage: CameraStorage[CameraStorageValues] = (
|
|
195
|
+
self.api.storage_controller.create_camera_storage(
|
|
196
|
+
self,
|
|
197
|
+
self.camera.id,
|
|
198
|
+
{
|
|
199
|
+
"motion_detector": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"key": "motion_detector",
|
|
202
|
+
"title": "Motion Detector",
|
|
203
|
+
"description": "Select the motion detection model to use",
|
|
204
|
+
"group": "Manage",
|
|
205
|
+
"enum": available_models,
|
|
206
|
+
"store": True,
|
|
207
|
+
"defaultValue": default_model,
|
|
208
|
+
"required": True,
|
|
209
|
+
"onSet": self.__change_model,
|
|
314
210
|
},
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
211
|
+
"default": {
|
|
212
|
+
"type": "object",
|
|
213
|
+
"key": "default",
|
|
214
|
+
"title": "Default",
|
|
215
|
+
"description": "Settings for the default model",
|
|
216
|
+
"group": "Default",
|
|
217
|
+
"opened": True,
|
|
218
|
+
"hidden": True,
|
|
219
|
+
"properties": {
|
|
220
|
+
"area": {
|
|
221
|
+
"type": "number",
|
|
222
|
+
"key": "area",
|
|
223
|
+
"title": "Area",
|
|
224
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
225
|
+
"store": True,
|
|
226
|
+
"defaultValue": default_area,
|
|
227
|
+
"minimum": 10,
|
|
228
|
+
"maximum": 1000,
|
|
229
|
+
"step": 1,
|
|
230
|
+
"required": True,
|
|
231
|
+
"onSet": lambda old, new: self.logger.log(
|
|
232
|
+
self.camera.name, f"Default model motion area changed from {old} to {new}"
|
|
233
|
+
),
|
|
234
|
+
},
|
|
235
|
+
"threshold": {
|
|
236
|
+
"type": "number",
|
|
237
|
+
"key": "threshold",
|
|
238
|
+
"title": "Threshold",
|
|
239
|
+
"description": "Sensitivity of motion detection (higher = less sensitive)",
|
|
240
|
+
"store": True,
|
|
241
|
+
"defaultValue": default_threshold,
|
|
242
|
+
"minimum": 1,
|
|
243
|
+
"maximum": 255,
|
|
244
|
+
"step": 1,
|
|
245
|
+
"required": True,
|
|
246
|
+
"onSet": lambda old, new: self.logger.log(
|
|
247
|
+
self.camera.name, f"Default model threshold changed from {old} to {new}"
|
|
248
|
+
),
|
|
249
|
+
},
|
|
250
|
+
"blur": {
|
|
251
|
+
"type": "number",
|
|
252
|
+
"key": "blur",
|
|
253
|
+
"title": "Blur",
|
|
254
|
+
"description": "Gaussian blur radius to reduce noise",
|
|
255
|
+
"store": True,
|
|
256
|
+
"defaultValue": default_blur,
|
|
257
|
+
"minimum": 1,
|
|
258
|
+
"maximum": 21,
|
|
259
|
+
"step": 1,
|
|
260
|
+
"required": True,
|
|
261
|
+
"onSet": lambda old, new: self.logger.log(
|
|
262
|
+
self.camera.name, f"Default model blur radius changed from {old} to {new}"
|
|
263
|
+
),
|
|
264
|
+
},
|
|
265
|
+
"dilation": {
|
|
266
|
+
"type": "number",
|
|
267
|
+
"key": "dilation",
|
|
268
|
+
"title": "Dilation",
|
|
269
|
+
"description": "Expansion of detected motion areas",
|
|
270
|
+
"store": True,
|
|
271
|
+
"defaultValue": default_dilt,
|
|
272
|
+
"minimum": 1,
|
|
273
|
+
"maximum": 21,
|
|
274
|
+
"step": 1,
|
|
275
|
+
"required": True,
|
|
276
|
+
"onSet": lambda old, new: self.logger.log(
|
|
277
|
+
self.camera.name,
|
|
278
|
+
f"Default model dilation size changed from {old} to {new}",
|
|
279
|
+
),
|
|
280
|
+
},
|
|
356
281
|
},
|
|
357
282
|
},
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
283
|
+
"background_substraction": {
|
|
284
|
+
"type": "object",
|
|
285
|
+
"key": "background_substraction",
|
|
286
|
+
"title": "Background Substraction",
|
|
287
|
+
"description": "Settings for the background substraction model",
|
|
288
|
+
"group": "Background Substraction",
|
|
289
|
+
"opened": True,
|
|
290
|
+
"hidden": True,
|
|
291
|
+
"properties": {
|
|
292
|
+
"area": {
|
|
293
|
+
"type": "number",
|
|
294
|
+
"key": "area",
|
|
295
|
+
"title": "Area",
|
|
296
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
297
|
+
"store": True,
|
|
298
|
+
"defaultValue": default_area_bs,
|
|
299
|
+
"minimum": 10,
|
|
300
|
+
"maximum": 1000,
|
|
301
|
+
"step": 1,
|
|
302
|
+
"required": True,
|
|
303
|
+
"onSet": lambda old, new: self.logger.log(
|
|
304
|
+
self.camera.name,
|
|
305
|
+
f"Background substraction model area changed from {old} to {new}",
|
|
306
|
+
),
|
|
307
|
+
},
|
|
308
|
+
"threshold": {
|
|
309
|
+
"type": "number",
|
|
310
|
+
"key": "threshold",
|
|
311
|
+
"title": "Threshold",
|
|
312
|
+
"description": "Sensitivity of motion detection (higher = less sensitive)",
|
|
313
|
+
"store": True,
|
|
314
|
+
"defaultValue": default_threshold_bs,
|
|
315
|
+
"minimum": 1,
|
|
316
|
+
"maximum": 255,
|
|
317
|
+
"step": 1,
|
|
318
|
+
"required": True,
|
|
319
|
+
"onSet": lambda old, new: self.logger.log(
|
|
320
|
+
self.camera.name,
|
|
321
|
+
f"Background substraction model threshold changed from {old} to {new}",
|
|
322
|
+
),
|
|
323
|
+
},
|
|
324
|
+
"learning_rate": {
|
|
325
|
+
"type": "number",
|
|
326
|
+
"key": "threshold",
|
|
327
|
+
"title": "Learning Rate",
|
|
328
|
+
"description": "Speed of background model adaptation (0-1, -1 for auto)",
|
|
329
|
+
"store": True,
|
|
330
|
+
"defaultValue": default_learning_rate,
|
|
331
|
+
"minimum": -1,
|
|
332
|
+
"maximum": 1,
|
|
333
|
+
"step": 0.01,
|
|
334
|
+
"required": True,
|
|
335
|
+
"onSet": lambda old, new: self.logger.log(
|
|
336
|
+
self.camera.name,
|
|
337
|
+
f"Background substraction model threshold changed from {old} to {new}",
|
|
338
|
+
),
|
|
339
|
+
},
|
|
382
340
|
},
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
"
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
341
|
+
},
|
|
342
|
+
"frame_difference": {
|
|
343
|
+
"type": "object",
|
|
344
|
+
"key": "frame_difference",
|
|
345
|
+
"title": "Frame Difference",
|
|
346
|
+
"description": "Settings for the frame difference model",
|
|
347
|
+
"group": "Frame Difference",
|
|
348
|
+
"opened": True,
|
|
349
|
+
"hidden": True,
|
|
350
|
+
"properties": {
|
|
351
|
+
"area": {
|
|
352
|
+
"type": "number",
|
|
353
|
+
"key": "area",
|
|
354
|
+
"title": "Area",
|
|
355
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
356
|
+
"store": True,
|
|
357
|
+
"defaultValue": default_area_fd,
|
|
358
|
+
"minimum": 10,
|
|
359
|
+
"maximum": 1000,
|
|
360
|
+
"step": 1,
|
|
361
|
+
"required": True,
|
|
362
|
+
"onSet": lambda old, new: self.logger.log(
|
|
363
|
+
self.camera.name,
|
|
364
|
+
f"Frame difference model area changed from {old} to {new}",
|
|
365
|
+
),
|
|
366
|
+
}
|
|
398
367
|
},
|
|
399
368
|
},
|
|
400
369
|
},
|
|
401
|
-
|
|
370
|
+
)
|
|
402
371
|
)
|
|
403
372
|
|
|
404
373
|
current_model = camera_storage.values["motion_detector"]
|
|
@@ -421,6 +390,7 @@ class CameraDetector:
|
|
|
421
390
|
|
|
422
391
|
old_schema = None
|
|
423
392
|
new_schema = None
|
|
393
|
+
self.previous_frame = None
|
|
424
394
|
|
|
425
395
|
if old_model == "Default":
|
|
426
396
|
old_schema = self.camera_storage.getSchema("default")
|
package/src/detector_defaults.py
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
default_area = 350
|
|
2
|
+
default_area_fd = 350
|
|
3
|
+
default_area_bs = 350
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
default_threshold = 50
|
|
6
|
+
default_threshold_bs = 50
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
default_blur = 11
|
|
9
|
+
default_dilt = 15
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
default_learning_rate = -1
|
|
12
12
|
|
|
13
13
|
available_models = ["Frame Difference", "Background Substraction", "Default"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
default_model = "Background Substraction"
|
package/src/main.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import tempfile
|
|
3
|
-
import time
|
|
4
3
|
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
-
from typing import Any, Union
|
|
4
|
+
from typing import Any, Optional, Union
|
|
6
5
|
|
|
7
6
|
import cv2
|
|
7
|
+
import numpy as np
|
|
8
8
|
from camera_detector import CameraDetector
|
|
9
9
|
from camera_ui_python_types import (
|
|
10
10
|
CameraDevice,
|
|
@@ -17,13 +17,15 @@ from camera_ui_python_types import (
|
|
|
17
17
|
RootSchema,
|
|
18
18
|
)
|
|
19
19
|
from detector_defaults import (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
default_area,
|
|
21
|
+
default_area_bs,
|
|
22
|
+
default_area_fd,
|
|
23
|
+
default_blur,
|
|
24
|
+
default_dilt,
|
|
25
|
+
default_learning_rate,
|
|
26
|
+
default_model,
|
|
27
|
+
default_threshold,
|
|
28
|
+
default_threshold_bs,
|
|
27
29
|
)
|
|
28
30
|
from opencv_utils import get_detections, get_detections_bs, get_detections_fd
|
|
29
31
|
|
|
@@ -96,7 +98,7 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
96
98
|
"description": "Select the motion detection model to use",
|
|
97
99
|
"enum": ["Frame Difference", "Background Substraction", "Default"],
|
|
98
100
|
"store": False,
|
|
99
|
-
"defaultValue":
|
|
101
|
+
"defaultValue": default_model,
|
|
100
102
|
"required": True,
|
|
101
103
|
},
|
|
102
104
|
"default": {
|
|
@@ -104,15 +106,17 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
104
106
|
"key": "default",
|
|
105
107
|
"title": "Default",
|
|
106
108
|
"description": "Settings for the default model",
|
|
107
|
-
"
|
|
109
|
+
"group": "Default",
|
|
110
|
+
"opened": True,
|
|
111
|
+
"hidden": True,
|
|
108
112
|
"properties": {
|
|
109
113
|
"area": {
|
|
110
114
|
"type": "number",
|
|
111
115
|
"key": "area",
|
|
112
116
|
"title": "Area",
|
|
113
|
-
"description": "Minimum
|
|
117
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
114
118
|
"store": False,
|
|
115
|
-
"defaultValue":
|
|
119
|
+
"defaultValue": default_area,
|
|
116
120
|
"minimum": 10,
|
|
117
121
|
"maximum": 1000,
|
|
118
122
|
"step": 1,
|
|
@@ -122,9 +126,9 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
122
126
|
"type": "number",
|
|
123
127
|
"key": "threshold",
|
|
124
128
|
"title": "Threshold",
|
|
125
|
-
"description": "
|
|
129
|
+
"description": "Sensitivity of motion detection (higher = less sensitive)",
|
|
126
130
|
"store": False,
|
|
127
|
-
"defaultValue":
|
|
131
|
+
"defaultValue": default_threshold,
|
|
128
132
|
"minimum": 1,
|
|
129
133
|
"maximum": 255,
|
|
130
134
|
"step": 1,
|
|
@@ -134,9 +138,9 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
134
138
|
"type": "number",
|
|
135
139
|
"key": "blur",
|
|
136
140
|
"title": "Blur",
|
|
137
|
-
"description": "
|
|
141
|
+
"description": "Gaussian blur radius to reduce noise",
|
|
138
142
|
"store": False,
|
|
139
|
-
"defaultValue":
|
|
143
|
+
"defaultValue": default_blur,
|
|
140
144
|
"minimum": 1,
|
|
141
145
|
"maximum": 21,
|
|
142
146
|
"step": 1,
|
|
@@ -146,26 +150,14 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
146
150
|
"type": "number",
|
|
147
151
|
"key": "dilation",
|
|
148
152
|
"title": "Dilation",
|
|
149
|
-
"description": "
|
|
153
|
+
"description": "Expansion of detected motion areas",
|
|
150
154
|
"store": False,
|
|
151
|
-
"defaultValue":
|
|
155
|
+
"defaultValue": default_dilt,
|
|
152
156
|
"minimum": 1,
|
|
153
157
|
"maximum": 21,
|
|
154
158
|
"step": 1,
|
|
155
159
|
"required": True,
|
|
156
160
|
},
|
|
157
|
-
"reference_frame_frequency": {
|
|
158
|
-
"type": "number",
|
|
159
|
-
"key": "reference_frame_frequency",
|
|
160
|
-
"title": "Reference Frame Frequency",
|
|
161
|
-
"description": "Frequency to update the reference frame",
|
|
162
|
-
"store": False,
|
|
163
|
-
"defaultValue": 5,
|
|
164
|
-
"minimum": 1,
|
|
165
|
-
"maximum": 60,
|
|
166
|
-
"step": 1,
|
|
167
|
-
"required": True,
|
|
168
|
-
},
|
|
169
161
|
},
|
|
170
162
|
},
|
|
171
163
|
"background_substraction": {
|
|
@@ -173,15 +165,17 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
173
165
|
"key": "background_substraction",
|
|
174
166
|
"title": "Background Substraction",
|
|
175
167
|
"description": "Settings for the background substraction model",
|
|
176
|
-
"
|
|
168
|
+
"group": "Background Substraction",
|
|
169
|
+
"opened": True,
|
|
170
|
+
"hidden": True,
|
|
177
171
|
"properties": {
|
|
178
172
|
"area": {
|
|
179
173
|
"type": "number",
|
|
180
174
|
"key": "area",
|
|
181
175
|
"title": "Area",
|
|
182
|
-
"description": "Minimum
|
|
176
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
183
177
|
"store": False,
|
|
184
|
-
"defaultValue":
|
|
178
|
+
"defaultValue": default_area_bs,
|
|
185
179
|
"minimum": 10,
|
|
186
180
|
"maximum": 1000,
|
|
187
181
|
"step": 1,
|
|
@@ -191,14 +185,26 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
191
185
|
"type": "number",
|
|
192
186
|
"key": "threshold",
|
|
193
187
|
"title": "Threshold",
|
|
194
|
-
"description": "
|
|
188
|
+
"description": "Sensitivity of motion detection (higher = less sensitive)",
|
|
195
189
|
"store": False,
|
|
196
|
-
"defaultValue":
|
|
190
|
+
"defaultValue": default_threshold_bs,
|
|
197
191
|
"minimum": 1,
|
|
198
192
|
"maximum": 255,
|
|
199
193
|
"step": 1,
|
|
200
194
|
"required": True,
|
|
201
195
|
},
|
|
196
|
+
"learning_rate": {
|
|
197
|
+
"type": "number",
|
|
198
|
+
"key": "threshold",
|
|
199
|
+
"title": "Learning Rate",
|
|
200
|
+
"description": "Speed of background model adaptation (0-1, -1 for auto)",
|
|
201
|
+
"store": False,
|
|
202
|
+
"defaultValue": default_learning_rate,
|
|
203
|
+
"minimum": -1,
|
|
204
|
+
"maximum": 1,
|
|
205
|
+
"step": 0.01,
|
|
206
|
+
"required": True,
|
|
207
|
+
},
|
|
202
208
|
},
|
|
203
209
|
},
|
|
204
210
|
"frame_difference": {
|
|
@@ -206,32 +212,22 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
206
212
|
"key": "frame_difference",
|
|
207
213
|
"title": "Frame Difference",
|
|
208
214
|
"description": "Settings for the frame difference model",
|
|
209
|
-
"
|
|
215
|
+
"group": "Frame Difference",
|
|
216
|
+
"opened": True,
|
|
217
|
+
"hidden": True,
|
|
210
218
|
"properties": {
|
|
211
219
|
"area": {
|
|
212
220
|
"type": "number",
|
|
213
221
|
"key": "area",
|
|
214
222
|
"title": "Area",
|
|
215
|
-
"description": "Minimum
|
|
223
|
+
"description": "Minimum size of detected motion (pixels)",
|
|
216
224
|
"store": False,
|
|
217
|
-
"defaultValue":
|
|
225
|
+
"defaultValue": default_area_fd,
|
|
218
226
|
"minimum": 10,
|
|
219
227
|
"maximum": 1000,
|
|
220
228
|
"step": 1,
|
|
221
229
|
"required": True,
|
|
222
|
-
}
|
|
223
|
-
"reference_frame_frequency": {
|
|
224
|
-
"type": "number",
|
|
225
|
-
"key": "reference_frame_frequency",
|
|
226
|
-
"title": "Reference Frame Frequency",
|
|
227
|
-
"description": "Frequency to update the reference frame",
|
|
228
|
-
"store": False,
|
|
229
|
-
"defaultValue": 5,
|
|
230
|
-
"minimum": 1,
|
|
231
|
-
"maximum": 60,
|
|
232
|
-
"step": 1,
|
|
233
|
-
"required": True,
|
|
234
|
-
},
|
|
230
|
+
}
|
|
235
231
|
},
|
|
236
232
|
},
|
|
237
233
|
}
|
|
@@ -251,8 +247,7 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
251
247
|
fourcc = cv2.VideoWriter.fourcc("a", "v", "c", "1")
|
|
252
248
|
out = cv2.VideoWriter(output_file, fourcc, fps, (width, height))
|
|
253
249
|
|
|
254
|
-
|
|
255
|
-
last_frame_time = 0
|
|
250
|
+
previous_frame: Optional[np.ndarray[Any, Any]] = None
|
|
256
251
|
backSub = None
|
|
257
252
|
|
|
258
253
|
detector_model = config.get("motion_detector", "Default")
|
|
@@ -263,35 +258,30 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
263
258
|
break
|
|
264
259
|
|
|
265
260
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
|
266
|
-
now = time.time() * 1000
|
|
267
261
|
|
|
268
262
|
if detector_model == "Frame Difference":
|
|
269
|
-
area = config.get("frame_difference", {}).get("area",
|
|
270
|
-
reference_frame_frequency = config.get("frame_difference", {}).get(
|
|
271
|
-
"reference_frame_frequency", defaultReferenceFrameFrequency
|
|
272
|
-
)
|
|
263
|
+
area = config.get("frame_difference", {}).get("area", default_area_fd)
|
|
273
264
|
|
|
274
|
-
if
|
|
275
|
-
|
|
276
|
-
):
|
|
277
|
-
first_frame = gray
|
|
278
|
-
last_frame_time = now
|
|
265
|
+
if previous_frame is None:
|
|
266
|
+
previous_frame = gray
|
|
279
267
|
continue
|
|
280
268
|
|
|
281
269
|
dets = await asyncio.get_event_loop().run_in_executor(
|
|
282
270
|
executor,
|
|
283
271
|
get_detections_fd,
|
|
284
|
-
|
|
272
|
+
previous_frame,
|
|
285
273
|
gray,
|
|
286
274
|
area,
|
|
287
275
|
)
|
|
288
276
|
|
|
277
|
+
previous_frame = gray
|
|
278
|
+
|
|
289
279
|
elif detector_model == "Background Substraction":
|
|
290
280
|
if backSub is None:
|
|
291
281
|
backSub = cv2.createBackgroundSubtractorMOG2(varThreshold=18, detectShadows=False)
|
|
292
282
|
|
|
293
|
-
threshold = config.get("background_substraction", {}).get("threshold",
|
|
294
|
-
area = config.get("background_substraction", {}).get("area",
|
|
283
|
+
threshold = config.get("background_substraction", {}).get("threshold", default_threshold_bs)
|
|
284
|
+
area = config.get("background_substraction", {}).get("area", default_area_bs)
|
|
295
285
|
|
|
296
286
|
dets = await asyncio.get_event_loop().run_in_executor(
|
|
297
287
|
executor,
|
|
@@ -303,31 +293,26 @@ class OpenCV(MotionDetectionPlugin):
|
|
|
303
293
|
)
|
|
304
294
|
|
|
305
295
|
else: # default
|
|
306
|
-
blur = config.get("default", {}).get("blur",
|
|
307
|
-
threshold = config.get("default", {}).get("threshold",
|
|
308
|
-
area = config.get("default", {}).get("area",
|
|
309
|
-
reference_frame_frequency = config.get("default", {}).get(
|
|
310
|
-
"reference_frame_frequency", defaultReferenceFrameFrequency
|
|
311
|
-
)
|
|
312
|
-
|
|
296
|
+
blur = config.get("default", {}).get("blur", default_blur)
|
|
297
|
+
threshold = config.get("default", {}).get("threshold", default_threshold)
|
|
298
|
+
area = config.get("default", {}).get("area", default_area)
|
|
313
299
|
gray = cv2.stackBlur(gray, (blur, blur))
|
|
314
300
|
|
|
315
|
-
if
|
|
316
|
-
|
|
317
|
-
):
|
|
318
|
-
first_frame = gray
|
|
319
|
-
last_frame_time = now
|
|
301
|
+
if previous_frame is None:
|
|
302
|
+
previous_frame = gray
|
|
320
303
|
continue
|
|
321
304
|
|
|
322
305
|
dets = await asyncio.get_event_loop().run_in_executor(
|
|
323
306
|
executor,
|
|
324
307
|
get_detections,
|
|
325
|
-
|
|
308
|
+
previous_frame,
|
|
326
309
|
gray,
|
|
327
310
|
threshold,
|
|
328
311
|
area,
|
|
329
312
|
)
|
|
330
313
|
|
|
314
|
+
previous_frame = gray
|
|
315
|
+
|
|
331
316
|
for det in dets:
|
|
332
317
|
(x1, y1, x2, y2) = det
|
|
333
318
|
|
package/src/opencv_utils.py
CHANGED
|
@@ -6,6 +6,7 @@ import numpy as np
|
|
|
6
6
|
DEFAULT_AREA_THRESHOLD = 500
|
|
7
7
|
DEFAULT_THRESHOLD = 50
|
|
8
8
|
DEFAULT_MASK_KERNEL = np.array((9, 9), dtype=np.uint8)
|
|
9
|
+
DEFAULT_LEARNING_RATE = 0.08
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def get_mask(
|
|
@@ -52,91 +53,6 @@ def get_contour_detections(
|
|
|
52
53
|
return detections
|
|
53
54
|
|
|
54
55
|
|
|
55
|
-
def is_in_bbox(point: tuple[float, float], bbox: tuple[float, float, float, float]) -> bool:
|
|
56
|
-
return point[0] >= bbox[0] and point[0] <= bbox[2] and point[1] >= bbox[1] and point[1] <= bbox[3]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
def intersect(bbox: tuple[float, float, float, float], bbox_: tuple[float, float, float, float]) -> bool:
|
|
60
|
-
for i in range(int(len(bbox) / 2)):
|
|
61
|
-
for j in range(int(len(bbox) / 2)):
|
|
62
|
-
# Check if one of the corner of bbox inside bbox_
|
|
63
|
-
if is_in_bbox((bbox[2 * i], bbox[2 * j + 1]), bbox_):
|
|
64
|
-
return True
|
|
65
|
-
return False
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def good_intersect(bbox: tuple[float, float, float, float], bbox_: tuple[float, float, float, float]) -> bool:
|
|
69
|
-
return bbox[0] < bbox_[2] and bbox[2] > bbox_[0] and bbox[1] < bbox_[3] and bbox[3] > bbox_[1]
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def calculate_iou(
|
|
73
|
-
bbox1: tuple[float, float, float, float], bbox2: tuple[float, float, float, float]
|
|
74
|
-
) -> float:
|
|
75
|
-
x1 = max(bbox1[0], bbox2[0])
|
|
76
|
-
y1 = max(bbox1[1], bbox2[1])
|
|
77
|
-
x2 = min(bbox1[2], bbox2[2])
|
|
78
|
-
y2 = min(bbox1[3], bbox2[3])
|
|
79
|
-
|
|
80
|
-
intersection_area = max(0, x2 - x1) * max(0, y2 - y1)
|
|
81
|
-
|
|
82
|
-
bbox1_area = (bbox1[2] - bbox1[0]) * (bbox1[3] - bbox1[1])
|
|
83
|
-
bbox2_area = (bbox2[2] - bbox2[0]) * (bbox2[3] - bbox2[1])
|
|
84
|
-
|
|
85
|
-
union_area = bbox1_area + bbox2_area - intersection_area
|
|
86
|
-
|
|
87
|
-
iou = intersection_area / union_area
|
|
88
|
-
|
|
89
|
-
return iou
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
def merge_bboxes(
|
|
93
|
-
bboxes: list[tuple[float, float, float, float]],
|
|
94
|
-
delta_x: float = 0.4,
|
|
95
|
-
delta_y: float = 0.4,
|
|
96
|
-
iou_threshold: float = 0,
|
|
97
|
-
) -> list[tuple[float, float, float, float]]:
|
|
98
|
-
# Sort bboxes by ymin
|
|
99
|
-
bboxes = sorted(bboxes, key=lambda x: x[1])
|
|
100
|
-
|
|
101
|
-
merged_bboxes: list[tuple[float, float, float, float]] = []
|
|
102
|
-
|
|
103
|
-
for bbox in bboxes:
|
|
104
|
-
is_merged = False
|
|
105
|
-
|
|
106
|
-
for i in range(len(merged_bboxes)):
|
|
107
|
-
merged_bbox = merged_bboxes[i]
|
|
108
|
-
|
|
109
|
-
# Compute the bboxes with a margin
|
|
110
|
-
bmargin: tuple[float, float, float, float] = (
|
|
111
|
-
bbox[0] - (bbox[2] - bbox[0]) * delta_x,
|
|
112
|
-
bbox[1] - (bbox[3] - bbox[1]) * delta_y,
|
|
113
|
-
bbox[2] + (bbox[2] - bbox[0]) * delta_x,
|
|
114
|
-
bbox[3] + (bbox[3] - bbox[1]) * delta_y,
|
|
115
|
-
)
|
|
116
|
-
merged_bmargin: tuple[float, float, float, float] = (
|
|
117
|
-
merged_bbox[0] - (merged_bbox[2] - merged_bbox[0]) * delta_x,
|
|
118
|
-
merged_bbox[1] - (merged_bbox[3] - merged_bbox[1]) * delta_y,
|
|
119
|
-
merged_bbox[2] + (merged_bbox[2] - merged_bbox[0]) * delta_x,
|
|
120
|
-
merged_bbox[3] + (merged_bbox[3] - merged_bbox[1]) * delta_y,
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
# Check if bboxes with margin have an intersection or if IoU is above the threshold
|
|
124
|
-
if intersect(bmargin, merged_bmargin) or calculate_iou(bbox, merged_bbox) >= iou_threshold:
|
|
125
|
-
merged_bboxes[i] = (
|
|
126
|
-
min(bbox[0], merged_bbox[0]),
|
|
127
|
-
min(bbox[1], merged_bbox[1]),
|
|
128
|
-
max(bbox[2], merged_bbox[2]),
|
|
129
|
-
max(bbox[3], merged_bbox[3]),
|
|
130
|
-
)
|
|
131
|
-
is_merged = True
|
|
132
|
-
break
|
|
133
|
-
|
|
134
|
-
if not is_merged:
|
|
135
|
-
merged_bboxes.append(bbox)
|
|
136
|
-
|
|
137
|
-
return merged_bboxes
|
|
138
|
-
|
|
139
|
-
|
|
140
56
|
def get_detections(
|
|
141
57
|
blurred_frame1: cv2.typing.MatLike,
|
|
142
58
|
blurred_frame2: cv2.typing.MatLike,
|
|
@@ -146,8 +62,7 @@ def get_detections(
|
|
|
146
62
|
delta_frame = cv2.absdiff(blurred_frame1, blurred_frame2)
|
|
147
63
|
thresh_frame = cv2.threshold(delta_frame, threshold, 255, cv2.THRESH_BINARY)[1]
|
|
148
64
|
thresh_frame = cast(cv2.typing.MatLike, cv2.dilate(thresh_frame, None, iterations=2)) # type: ignore
|
|
149
|
-
|
|
150
|
-
return merge_bboxes(detections)
|
|
65
|
+
return get_contour_detections(thresh_frame, area_threshold)
|
|
151
66
|
|
|
152
67
|
|
|
153
68
|
def get_detections_fd(
|
|
@@ -156,8 +71,7 @@ def get_detections_fd(
|
|
|
156
71
|
area_threshold: int = DEFAULT_AREA_THRESHOLD,
|
|
157
72
|
) -> list[tuple[float, float, float, float]]:
|
|
158
73
|
mask = get_mask(frame1, frame2, DEFAULT_MASK_KERNEL)
|
|
159
|
-
|
|
160
|
-
return merge_bboxes(detections)
|
|
74
|
+
return get_contour_detections(mask, area_threshold)
|
|
161
75
|
|
|
162
76
|
|
|
163
77
|
def get_detections_bs(
|
|
@@ -165,8 +79,8 @@ def get_detections_bs(
|
|
|
165
79
|
backSub: Union[cv2.BackgroundSubtractorMOG2, cv2.BackgroundSubtractorKNN],
|
|
166
80
|
threshold: int = DEFAULT_THRESHOLD,
|
|
167
81
|
area_threshold: int = DEFAULT_AREA_THRESHOLD,
|
|
82
|
+
learning_rate: float = DEFAULT_LEARNING_RATE,
|
|
168
83
|
) -> list[tuple[float, float, float, float]]:
|
|
169
|
-
fg_mask = backSub.apply(frame)
|
|
84
|
+
fg_mask = backSub.apply(frame, learningRate=learning_rate)
|
|
170
85
|
motion_mask = get_motion_mask(fg_mask, threshold=threshold)
|
|
171
|
-
|
|
172
|
-
return merge_bboxes(detections)
|
|
86
|
+
return get_contour_detections(motion_mask, area_threshold)
|
package/src/plugin_typings.py
CHANGED
|
@@ -8,17 +8,18 @@ class DefaultModelValues(TypedDict):
|
|
|
8
8
|
threshold: int
|
|
9
9
|
blur: int
|
|
10
10
|
dilation: int
|
|
11
|
-
reference_frame_frequency: int
|
|
11
|
+
# reference_frame_frequency: int
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
class BackgroundSubstractionValues(TypedDict):
|
|
15
15
|
area: int
|
|
16
16
|
threshold: int
|
|
17
|
+
learning_rate: float
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class FrameDifferenceValues(TypedDict):
|
|
20
21
|
area: int
|
|
21
|
-
reference_frame_frequency: int
|
|
22
|
+
# reference_frame_frequency: int
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class CameraStorageValues(TypedDict):
|