@@ -1 +1 @@
|
||||
__version__ = '0.5.0'
|
||||
__version__ = '0.6.0'
|
||||
|
||||
@@ -31,8 +31,8 @@ class function_display_callback(object): # NOSONAR
|
||||
... array[coords[0:2]] = (array[coords[0:2]] + [r,g,b])%1.0
|
||||
>>> VideoHandlerThread(video_source=img, callbacks=function_display_callback(fun)).display()
|
||||
|
||||
:param display_function:
|
||||
:param finish_function:
|
||||
:param display_function: a function to run on the input image.
|
||||
:param finish_function: a function to run on the input image when the other function finishes.
|
||||
"""
|
||||
self.looping = True
|
||||
self.first_call = True
|
||||
@@ -4,13 +4,15 @@ import numpy as np
|
||||
|
||||
from cvpubsubs.webcam_pub.pub_cam import pub_cam_thread
|
||||
from cvpubsubs.webcam_pub.camctrl import CamCtrl
|
||||
from cvpubsubs.window_sub.winctrl import WinCtrl
|
||||
|
||||
|
||||
if False:
|
||||
from typing import Union, Tuple, Any, Callable, List, Optional
|
||||
|
||||
FrameCallable = Callable[[np.ndarray, int], Optional[np.ndarray]]
|
||||
|
||||
from cvpubsubs.webcam_pub.callbacks import global_cv_display_callback
|
||||
from cvpubsubs.callbacks import global_cv_display_callback
|
||||
|
||||
display_callbacks = [global_cv_display_callback]
|
||||
|
||||
@@ -53,6 +55,7 @@ class VideoHandlerThread(threading.Thread):
|
||||
self.request_size = request_size
|
||||
self.high_speed = high_speed
|
||||
self.fps_limit = fps_limit
|
||||
self.exception_raised = None
|
||||
|
||||
def loop(self):
|
||||
"""Continually gets frames from the video publisher, runs callbacks on them, and listens to commands."""
|
||||
@@ -66,7 +69,14 @@ class VideoHandlerThread(threading.Thread):
|
||||
frame = sub_cam.get(blocking=True, timeout=1.0) # type: np.ndarray
|
||||
if frame is not None:
|
||||
for c in self.callbacks:
|
||||
frame_c = c(frame, self.cam_id)
|
||||
try:
|
||||
frame_c = c(frame, self.cam_id)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
CamCtrl.stop_cam(self.cam_id)
|
||||
WinCtrl.quit()
|
||||
self.exception_raised = e
|
||||
frame_c = self.exception_raised
|
||||
if frame_c is not None:
|
||||
frame = frame_c
|
||||
msg_owner = sub_owner.get()
|
||||
@@ -93,3 +103,5 @@ class VideoHandlerThread(threading.Thread):
|
||||
self.start()
|
||||
SubscriberWindows(video_sources=[self.cam_id], callbacks=callbacks).loop()
|
||||
self.join()
|
||||
if self.exception_raised is not None:
|
||||
raise self.exception_raised
|
||||
|
||||
@@ -40,9 +40,9 @@ class SubscriberWindows(object):
|
||||
@staticmethod
|
||||
def set_global_frame_dict(name, *args):
|
||||
if len(str(name)) <= 1000:
|
||||
SubscriberWindows.frame_dict[str(name) + "frame"] = [*args]
|
||||
SubscriberWindows.frame_dict[str(name) + "frame"] = list(args)
|
||||
elif isinstance(name, np.ndarray):
|
||||
SubscriberWindows.frame_dict[str(hash(str(name))) + "frame"] = [*args]
|
||||
SubscriberWindows.frame_dict[str(hash(str(name))) + "frame"] = list(args)
|
||||
else:
|
||||
raise ValueError("Input window name too long.")
|
||||
|
||||
@@ -68,6 +68,8 @@ class SubscriberWindows(object):
|
||||
)
|
||||
|
||||
def _display_frames(self, frames, win_num):
|
||||
if isinstance(frames, Exception):
|
||||
raise frames
|
||||
for f in range(len(frames)):
|
||||
# detect nested:
|
||||
if isinstance(frames[f], (list, tuple)) or frames[f].dtype.num == 17 or len(frames[f].shape) > 3:
|
||||
|
||||
+28
-3
@@ -1,8 +1,6 @@
|
||||
import threading
|
||||
import unittest as ut
|
||||
|
||||
import numpy as np
|
||||
|
||||
import cvpubsubs.webcam_pub as w
|
||||
from cvpubsubs.window_sub import SubscriberWindows
|
||||
from cvpubsubs.window_sub.winctrl import WinCtrl
|
||||
@@ -61,6 +59,16 @@ class TestSubWin(ut.TestCase):
|
||||
|
||||
w.VideoHandlerThread(callbacks=redden_frame_print_spam).display()
|
||||
|
||||
def test_sub_with_callback_exception(self):
|
||||
def redden_frame_print_spam(frame, cam_id):
|
||||
frame[:, :, 0] = 0
|
||||
frame[:, :, 2] = 1 / 0
|
||||
|
||||
with self.assertRaises(ZeroDivisionError) as e:
|
||||
v = w.VideoHandlerThread(callbacks=redden_frame_print_spam)
|
||||
v.display()
|
||||
self.assertEqual(v.exception_raised, e)
|
||||
|
||||
def test_multi_cams_one_source(self):
|
||||
def cam_handler(frame, cam_id):
|
||||
SubscriberWindows.set_global_frame_dict(cam_id, frame, frame)
|
||||
@@ -108,9 +116,26 @@ class TestSubWin(ut.TestCase):
|
||||
|
||||
v.join()
|
||||
|
||||
def test_nested_frames_exception(self):
|
||||
def nest_frame(frame, cam_id):
|
||||
frame = np.asarray([[[[[[frame + 1 / 0]]]]], [[[[[frame]]], [[[frame]]]]]])
|
||||
return frame
|
||||
|
||||
v = w.VideoHandlerThread(callbacks=[nest_frame] + w.display_callbacks)
|
||||
v.start()
|
||||
|
||||
with self.assertRaises(ZeroDivisionError) as e:
|
||||
SubscriberWindows(window_names=[str(i) for i in range(3)],
|
||||
video_sources=[str(0)]
|
||||
).loop()
|
||||
self.assertEqual(v.exception_raised, e)
|
||||
|
||||
v.join()
|
||||
|
||||
def test_conway_life(self):
|
||||
from cvpubsubs.webcam_pub import VideoHandlerThread
|
||||
from cvpubsubs.webcam_pub.callbacks import function_display_callback
|
||||
from cvpubsubs.callbacks import function_display_callback
|
||||
import numpy as np
|
||||
img = np.zeros((50, 50, 1))
|
||||
img[0:5, 0:5, :] = 1
|
||||
|
||||
|
||||
Reference in New Issue
Block a user