From 833b783188ad37b5300cad4588ef02ec49805279 Mon Sep 17 00:00:00 2001 From: simleek Date: Thu, 14 May 2020 20:15:14 -0700 Subject: [PATCH 1/2] One camera can now be accessed by two seperate pieces of code. Updated minor version. --- displayarray/__init__.py | 2 +- displayarray/frame/frame_publishing.py | 44 ++++++++++++++--------- displayarray/window/subscriber_windows.py | 1 - examples/looping/one_cam_two_codes.py | 10 ++++++ pyproject.toml | 2 +- 5 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 examples/looping/one_cam_two_codes.py diff --git a/displayarray/__init__.py b/displayarray/__init__.py index 2d6474d..fd8215c 100644 --- a/displayarray/__init__.py +++ b/displayarray/__init__.py @@ -4,7 +4,7 @@ Display any array, webcam, or video file. display is a function that displays these in their own windows. """ -__version__ = "1.0.0" +__version__ = "1.1.0" from .window.subscriber_windows import display, breakpoint_display, read_updates from .frame.frame_publishing import publish_updates_zero_mq, publish_updates_ros diff --git a/displayarray/frame/frame_publishing.py b/displayarray/frame/frame_publishing.py index 2031031..29934af 100644 --- a/displayarray/frame/frame_publishing.py +++ b/displayarray/frame/frame_publishing.py @@ -1,11 +1,12 @@ """Publish frames so any function within this program can find them.""" +import asyncio +import sys import threading import time -import asyncio -import cv2 import warnings -import sys + +import cv2 using_pyv4l2cam = False try: @@ -123,6 +124,7 @@ def pub_cam_loop_opencv( request_size: Tuple[int, int] = (-1, -1), high_speed: bool = True, fps_limit: float = float("inf"), + extra: Optional[List[Tuple[int, int]]] = None, ) -> bool: """ Publish whichever camera you select to CVCams..Vid. @@ -186,6 +188,9 @@ def pub_cam_loop_opencv( return True +uid_dict: Dict[str, threading.Thread] = {} + + def pub_cam_thread( cam_id: Union[int, str], request_ize: Tuple[int, int] = (-1, -1), @@ -194,22 +199,27 @@ def pub_cam_thread( ) -> threading.Thread: """Run pub_cam_loop in a new thread. Starts on creation.""" - if ( - sys.platform == "linux" - and using_pyv4l2cam - and ( - isinstance(cam_id, int) - or (isinstance(cam_id, str) and "/dev/video" in cam_id) - ) - ): - pub_cam_loop = pub_cam_loop_pyv4l2 + name = uid_for_source(cam_id) + if name in uid_dict.keys(): + t = uid_dict[name] else: - pub_cam_loop = pub_cam_loop_opencv + if ( + sys.platform == "linux" + and using_pyv4l2cam + and ( + isinstance(cam_id, int) + or (isinstance(cam_id, str) and "/dev/video" in cam_id) + ) + ): + pub_cam_loop = pub_cam_loop_pyv4l2 + else: + pub_cam_loop = pub_cam_loop_opencv - t = threading.Thread( - target=pub_cam_loop, args=(cam_id, request_ize, high_speed, fps_limit) - ) - t.start() + t = threading.Thread( + target=pub_cam_loop, args=(cam_id, request_ize, high_speed, fps_limit) + ) + uid_dict[name] = t + t.start() return t diff --git a/displayarray/window/subscriber_windows.py b/displayarray/window/subscriber_windows.py index c460f42..5c47ce1 100644 --- a/displayarray/window/subscriber_windows.py +++ b/displayarray/window/subscriber_windows.py @@ -211,7 +211,6 @@ class SubscriberWindows(object): self.frames[self.input_vid_global_names[i]][-1] = frame if not self.silent: self.__check_too_many_channels() - self.FRAME_DICT[self.input_vid_global_names[i]] = NoData() if not self.silent: self.display_frames(self.frames) diff --git a/examples/looping/one_cam_two_codes.py b/examples/looping/one_cam_two_codes.py new file mode 100644 index 0000000..036850e --- /dev/null +++ b/examples/looping/one_cam_two_codes.py @@ -0,0 +1,10 @@ +from displayarray import read_updates + +with read_updates(0) as a, read_updates(0) as b: + for i in range(1000): + a.update() + b.update() + try: + print(a.frames == b.frames) + except ValueError: + print(f"frame comparison: {(a.frames['0'][0] == b.frames['0'][0]).all()}") diff --git a/pyproject.toml b/pyproject.toml index e034d15..230f961 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = 'displayarray' -version = '1.0.0' +version = '1.1.0' description = 'Tool for displaying numpy arrays.' authors = ['SimLeek '] license = 'MIT' From 96fcaa733ee2d1cd4fbd75324a41d8246bd74fcd Mon Sep 17 00:00:00 2001 From: simleek Date: Thu, 14 May 2020 21:32:56 -0700 Subject: [PATCH 2/2] fixed tests hanging forever due to frame dict not being cleared. --- displayarray/frame/frame_updater.py | 20 ++++++++++++-------- tests/frame/test_frame_updater.py | 5 ++--- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/displayarray/frame/frame_updater.py b/displayarray/frame/frame_updater.py index b76d68a..4cd79a1 100644 --- a/displayarray/frame/frame_updater.py +++ b/displayarray/frame/frame_updater.py @@ -91,14 +91,18 @@ class FrameUpdater(threading.Thread): sub_cam = subscriber_dictionary.cam_frame_sub(str(self.cam_id)) sub_owner = subscriber_dictionary.handler_cmd_sub(str(self.cam_id)) msg_owner = sub_owner.return_on_no_data = "" - while msg_owner != "quit": - frame = sub_cam.get(blocking=True, timeout=1.0) # type: np.ndarray - self.__apply_callbacks_to_frame(frame) - msg_owner = sub_owner.get() - sub_owner.release() - sub_cam.release() - subscriber_dictionary.stop_cam(self.cam_id) - t.join() + try: + while msg_owner != "quit": + frame = sub_cam.get(blocking=True, timeout=1.0) # type: np.ndarray + self.__apply_callbacks_to_frame(frame) + msg_owner = sub_owner.get() + except Exception as e: + raise e + finally: + sub_owner.release() + sub_cam.release() + subscriber_dictionary.stop_cam(self.cam_id) + t.join() def display(self, callbacks: List[Callable[[np.ndarray], Any]] = None): """ diff --git a/tests/frame/test_frame_updater.py b/tests/frame/test_frame_updater.py index 3230511..1fe291e 100644 --- a/tests/frame/test_frame_updater.py +++ b/tests/frame/test_frame_updater.py @@ -75,7 +75,7 @@ def test_callback_exception(): frame[:, :, 2] = 1 / 0 with pytest.raises(ZeroDivisionError) as e: - v = fup.FrameUpdater(np.zeros((1, 1, 3)), callbacks=redden_frame_print_spam) + v = fup.FrameUpdater(np.zeros((1, 2, 3)), callbacks=redden_frame_print_spam) v.loop() assert e.errisinstance(ZeroDivisionError) @@ -92,8 +92,6 @@ def test_display(): mock_sub_win.assert_called_once_with(video_sources=["0"], callbacks=[]) mock_sub_win_instance.loop.assert_called_once() - f.start.assert_called_once() - f.join.assert_called_once() def test_display_exception(): @@ -109,6 +107,7 @@ def test_display_exception(): v = fup.FrameUpdater(np.zeros((1, 1, 3)), callbacks=redden_frame_print_spam) v.display() assert e.errisinstance(ZeroDivisionError) + # todo: clear the frame dict so that these don't hang forever from displayarray.window.window_commands import win_cmd_pub