Skip to content

Commit 8cfa61e

Browse files
committed
[app] Simplify main UI
Move motion/scan settings under main "Settings..." window.
1 parent c722b12 commit 8cfa61e

File tree

2 files changed

+76
-67
lines changed

2 files changed

+76
-67
lines changed

dvr_scan/app/application.py

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -340,30 +340,51 @@ def start_end_time(self) -> ty.Optional[ty.Tuple[str, str]]:
340340
return self._start_time.get(), self._end_time.get()
341341

342342

343-
class SettingsArea:
343+
class SettingsWindow:
344344
def __init__(self, root: tk.Widget):
345345
self._root = root
346-
self._advanced = tk.Toplevel(master=root)
347-
self._advanced.withdraw()
346+
self._window = tk.Toplevel(master=root)
347+
self._window.withdraw()
348348

349349
root.rowconfigure(0, pad=PADDING, weight=1)
350-
root.rowconfigure(1, pad=PADDING, weight=1)
351-
root.rowconfigure(2, pad=PADDING, weight=1)
352350
root.columnconfigure(0, pad=PADDING, weight=1)
353-
root.columnconfigure(1, pad=PADDING, weight=1)
354-
root.columnconfigure(2, pad=PADDING, weight=2)
355-
root.columnconfigure(3, pad=PADDING, weight=1)
356-
root.columnconfigure(4, pad=PADDING, weight=1)
357-
root.columnconfigure(5, pad=PADDING, weight=1)
358-
root.columnconfigure(6, pad=PADDING, weight=12, minsize=0)
351+
root.columnconfigure(1, pad=PADDING, weight=12, minsize=0)
352+
353+
STICKY = tk.EW
354+
355+
#
356+
#
357+
# Advanced Window
358+
#
359+
#
360+
self._window.minsize(width=MIN_WINDOW_WIDTH, height=MIN_WINDOW_HEIGHT)
361+
self._window.title("Motion Settings")
362+
self._window.resizable(True, True)
363+
self._window.protocol("WM_DELETE_WINDOW", self._dismiss_advanced)
364+
self._window.rowconfigure(0, weight=1)
365+
self._window.rowconfigure(1, weight=1)
366+
self._window.columnconfigure(0, weight=1)
367+
368+
frame = ttk.LabelFrame(self._window, text="Motion", padding=PADDING)
369+
frame.grid(row=0, sticky=tk.NSEW, padx=PADDING, pady=PADDING)
370+
frame.rowconfigure(0, pad=PADDING, weight=1)
371+
frame.rowconfigure(1, pad=PADDING, weight=1)
372+
frame.rowconfigure(2, pad=PADDING, weight=1)
373+
frame.columnconfigure(0, pad=PADDING, weight=1)
374+
frame.columnconfigure(1, pad=PADDING, weight=1)
375+
frame.columnconfigure(2, pad=PADDING, weight=2)
376+
frame.columnconfigure(3, pad=PADDING, weight=1)
377+
frame.columnconfigure(4, pad=PADDING, weight=1)
378+
frame.columnconfigure(5, pad=PADDING, weight=1)
379+
frame.columnconfigure(6, pad=PADDING, weight=12, minsize=0)
359380

360381
STICKY = tk.EW
361382

362383
# Detector
363384

364-
tk.Label(root, text="Subtractor").grid(row=0, column=0, sticky=STICKY)
385+
tk.Label(frame, text="Subtractor").grid(row=0, column=0, sticky=STICKY)
365386
self._bg_subtractor = tk.StringVar()
366-
combo = ttk.Combobox(root, textvariable=self._bg_subtractor, width=SETTING_INPUT_WIDTH)
387+
combo = ttk.Combobox(frame, textvariable=self._bg_subtractor, width=SETTING_INPUT_WIDTH)
367388
combo.state(["readonly"])
368389
if SubtractorCudaMOG2.is_available():
369390
combo["values"] = ("MOG2_CUDA", "MOG2", "CNT")
@@ -374,9 +395,11 @@ def __init__(self, root: tk.Widget):
374395

375396
combo.grid(row=0, column=1, sticky=STICKY)
376397

377-
tk.Label(root, text="Kernel Size").grid(row=1, column=0, sticky=STICKY)
398+
tk.Label(frame, text="Kernel Size").grid(row=1, column=0, sticky=STICKY)
378399

379-
self._kernel_size_combobox = ttk.Combobox(root, width=SETTING_INPUT_WIDTH, state="readonly")
400+
self._kernel_size_combobox = ttk.Combobox(
401+
frame, width=SETTING_INPUT_WIDTH, state="readonly"
402+
)
380403
# 0: Auto
381404
# 1: Off
382405
# 2: 3x3
@@ -391,9 +414,9 @@ def __init__(self, root: tk.Widget):
391414
self._kernel_size_combobox.grid(row=1, column=1, sticky=STICKY)
392415
self._kernel_size_combobox.current(1)
393416

394-
tk.Label(root, text="Threshold").grid(row=2, column=0, sticky=STICKY)
417+
tk.Label(frame, text="Threshold").grid(row=2, column=0, sticky=STICKY)
395418
self._threshold = Spinbox(
396-
root,
419+
frame,
397420
value=str(CONFIG_MAP["threshold"]),
398421
from_=0.0,
399422
to=255.0,
@@ -402,9 +425,9 @@ def __init__(self, root: tk.Widget):
402425
self._threshold.grid(row=2, column=1, sticky=STICKY)
403426

404427
# Events
405-
tk.Label(root, text="Min. Event Length").grid(row=0, column=3, sticky=STICKY)
428+
tk.Label(frame, text="Min. Event Length").grid(row=0, column=3, sticky=STICKY)
406429
self._min_event_length = Spinbox(
407-
root,
430+
frame,
408431
value=str(CONFIG_MAP["min-event-length"]),
409432
from_=0.0,
410433
to=MAX_DURATION,
@@ -413,9 +436,9 @@ def __init__(self, root: tk.Widget):
413436
)
414437
self._min_event_length.grid(row=0, column=4, sticky=STICKY)
415438

416-
tk.Label(root, text="Time Pre-Event").grid(row=1, column=3, sticky=STICKY)
439+
tk.Label(frame, text="Time Pre-Event").grid(row=1, column=3, sticky=STICKY)
417440
self._time_before_event = Spinbox(
418-
root,
441+
frame,
419442
value=str(CONFIG_MAP["time-before-event"]),
420443
from_=0.0,
421444
to=MAX_DURATION,
@@ -424,9 +447,9 @@ def __init__(self, root: tk.Widget):
424447
)
425448
self._time_before_event.grid(row=1, column=4, sticky=STICKY)
426449

427-
tk.Label(root, text="Time Post-Event").grid(row=2, column=3, sticky=STICKY)
450+
tk.Label(frame, text="Time Post-Event").grid(row=2, column=3, sticky=STICKY)
428451
self._time_post_event = Spinbox(
429-
root,
452+
frame,
430453
value=str(CONFIG_MAP["time-post-event"]),
431454
from_=0.0,
432455
to=MAX_DURATION,
@@ -437,35 +460,15 @@ def __init__(self, root: tk.Widget):
437460

438461
self._mask_output = tk.BooleanVar(value=False)
439462
ttk.Checkbutton(
440-
root,
463+
frame,
441464
text="Save Motion Mask",
442465
variable=self._mask_output,
443466
onvalue=True,
444467
offvalue=False,
445468
).grid(row=3, column=0, columnspan=2, sticky=tk.W, padx=PADDING, pady=PADDING)
446469

447-
# Processing
448-
449-
self._advanced_button = ttk.Button(
450-
root, text="Advanced...", command=self._show_advanced, width=SETTING_INPUT_WIDTH
451-
)
452-
self._advanced_button.grid(
453-
row=3, column=3, columnspan=2, sticky=tk.EW, pady=PADDING, padx=PADDING
454-
)
455-
456-
#
457-
#
458-
# Advanced Window
459-
#
460-
#
461-
self._advanced.minsize(width=MIN_WINDOW_WIDTH, height=MIN_WINDOW_HEIGHT)
462-
self._advanced.title("Motion Settings")
463-
self._advanced.resizable(True, True)
464-
self._advanced.protocol("WM_DELETE_WINDOW", self._dismiss_advanced)
465-
self._advanced.rowconfigure(0, weight=1)
466-
self._advanced.columnconfigure(0, weight=1)
467-
frame = ttk.LabelFrame(self._advanced, text="Advanced", padding=PADDING)
468-
frame.grid(row=0, sticky=tk.NSEW, padx=PADDING, pady=PADDING)
470+
frame = ttk.LabelFrame(self._window, text="Advanced", padding=PADDING)
471+
frame.grid(row=1, sticky=tk.NSEW, padx=PADDING, pady=PADDING)
469472
frame.columnconfigure(0, weight=1)
470473
frame.columnconfigure(1, weight=1)
471474
frame.columnconfigure(2, weight=2)
@@ -541,8 +544,8 @@ def __init__(self, root: tk.Widget):
541544
offvalue=False,
542545
).grid(row=2, column=0, columnspan=2, padx=PADDING, sticky=STICKY, pady=PADDING)
543546

544-
tk.Button(self._advanced, text="Close", command=self._dismiss_advanced).grid(
545-
row=1, column=0, sticky=tk.E, padx=PADDING, pady=PADDING
547+
tk.Button(self._window, text="Close", command=self._dismiss_advanced).grid(
548+
row=2, column=0, sticky=tk.E, padx=PADDING, pady=PADDING
546549
)
547550

548551
tk.Label(frame, text="Frame Skip").grid(
@@ -562,19 +565,19 @@ def _on_auto_learning_rate(self):
562565
tk.DISABLED if self._learning_rate_auto.get() else tk.NORMAL
563566
)
564567

565-
def _show_advanced(self):
568+
def show(self):
566569
logger.debug("showing advanced settings window")
567-
self._advanced.transient(self._root)
568-
self._advanced.deiconify()
569-
self._advanced.focus()
570-
self._advanced.grab_set()
571-
self._advanced.wait_window()
570+
self._window.transient(self._root)
571+
self._window.deiconify()
572+
self._window.focus()
573+
self._window.grab_set()
574+
self._window.wait_window()
572575

573576
def _dismiss_advanced(self):
574577
logger.debug("closing advanced settings window")
575-
self._advanced.withdraw()
576-
self._advanced.grab_release()
577-
self._advanced_button.focus()
578+
self._window.withdraw()
579+
self._window.grab_release()
580+
self._root.focus()
578581

579582
@property
580583
def _kernel_size(self) -> int:
@@ -1168,28 +1171,27 @@ def __init__(self, settings: ScanSettings, initial_videos: ty.List[str]):
11681171
self._root.columnconfigure(0, weight=1, pad=PADDING)
11691172
self._root.rowconfigure(0, weight=1)
11701173

1171-
self._create_menubar()
1172-
11731174
input_frame = ttk.Labelframe(self._root, text="Input", padding=PADDING)
11741175
self._input_area = InputArea(input_frame)
11751176
input_frame.grid(row=0, sticky=tk.NSEW, padx=PADDING, pady=(PADDING, 0))
11761177

1177-
settings_frame = ttk.Labelframe(self._root, text="Motion", padding=PADDING)
1178-
self._settings_area = SettingsArea(settings_frame)
1179-
settings_frame.grid(row=1, sticky=tk.EW, padx=PADDING, pady=(PADDING, 0))
1178+
# settings_frame = ttk.Labelframe(self._root, text="Scanner", padding=PADDING)
1179+
self._settings_area = SettingsWindow(self._root)
11801180

11811181
output_frame = ttk.Labelframe(self._root, text="Output", padding=PADDING)
11821182
self._output_area = OutputArea(output_frame)
11831183
output_frame.grid(row=2, sticky=tk.EW, padx=PADDING, pady=(PADDING, 0))
11841184

1185-
scan_frame = ttk.Labelframe(self._root, text="Scan", padding=PADDING)
1185+
scan_frame = ttk.Labelframe(self._root, text="Run", padding=PADDING)
11861186
self._scan_area = ScanArea(self._root, scan_frame)
11871187
scan_frame.grid(row=3, sticky=tk.EW, padx=PADDING, pady=PADDING)
11881188

11891189
self._scan_window: ty.Optional[ScanWindow] = None
11901190
self._root.bind("<<StartScan>>", lambda _: self._start_scan())
11911191
self._root.protocol("WM_DELETE_WINDOW", self._destroy)
11921192

1193+
self._create_menubar()
1194+
11931195
if not SUPPRESS_EXCEPTIONS:
11941196

11951197
def error_handler(*args):
@@ -1223,6 +1225,13 @@ def _create_menubar(self):
12231225

12241226
settings_menu = tk.Menu(root_menu)
12251227
root_menu.add_cascade(menu=settings_menu, label="Settings", underline=0)
1228+
# TODO(#201): Add ability to change input settings.
1229+
settings_menu.add_command(
1230+
label="Motion",
1231+
underline=0,
1232+
command=self._settings_area.show,
1233+
)
1234+
settings_menu.add_separator()
12261235
settings_menu.add_command(
12271236
label="Load...",
12281237
underline=0,

dvr_scan/video_joiner.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import cv2
2222
import numpy
2323
from scenedetect import FrameTimecode
24-
from scenedetect.backends import VideoStreamCv2
24+
from scenedetect.backends import VideoStreamAv
2525
from scenedetect.video_stream import VideoOpenFailure
2626

2727
FRAMERATE_DELTA_TOLERANCE: float = 0.1
@@ -44,7 +44,7 @@ def __init__(self, paths: Union[AnyStr, List[AnyStr]]):
4444
assert paths
4545
self._paths = paths
4646

47-
self._cap: Optional[VideoStreamCv2] = None
47+
self._cap: Optional[VideoStreamAv] = None
4848
self._curr_cap_index = 0
4949
self._total_frames: int = 0
5050
self._decode_failures: int = 0
@@ -99,7 +99,7 @@ def read(self, decode: bool = True) -> Optional[numpy.ndarray]:
9999
logger.debug(
100100
"End of current video, loading next: %s" % self._paths[self._curr_cap_index]
101101
)
102-
self._cap = VideoStreamCv2(self._paths[self._curr_cap_index])
102+
self._cap = VideoStreamAv(self._paths[self._curr_cap_index])
103103
self._last_cap_pos = self._cap.base_timecode
104104
return self.read(decode=decode)
105105
logger.debug("No more input to process.")
@@ -127,7 +127,7 @@ def _load_input_videos(self):
127127
for video_path in self._paths:
128128
video_name = os.path.basename(video_path)
129129
try:
130-
cap = VideoStreamCv2(video_path)
130+
cap = VideoStreamAv(video_path)
131131
except VideoOpenFailure:
132132
logger.error("Error: Couldn't load video %s", video_path)
133133
raise

0 commit comments

Comments
 (0)