frames are now stored and returned as dictionaries with source name as key. Set to version 1.0.0 because this is a major breaking change.

This commit is contained in:
simleek
2020-04-29 13:21:12 -07:00
parent 18335d6260
commit 337dd5f276
4 changed files with 102 additions and 75 deletions

View File

@ -4,7 +4,7 @@ Display any array, webcam, or video file.
display is a function that displays these in their own windows. display is a function that displays these in their own windows.
""" """
__version__ = "0.7.5" __version__ = "1.0.0"
from .window.subscriber_windows import display, breakpoint_display, read_updates from .window.subscriber_windows import display, breakpoint_display, read_updates
from .frame.frame_publishing import publish_updates_zero_mq, publish_updates_ros from .frame.frame_publishing import publish_updates_zero_mq, publish_updates_ros

View File

@ -35,7 +35,7 @@ class SubscriberWindows(object):
"""Create the array displaying window.""" """Create the array displaying window."""
self.source_names: List[Union[str, int]] = [] self.source_names: List[Union[str, int]] = []
self.close_threads: Optional[List[Thread]] = [] self.close_threads: Optional[List[Thread]] = []
self.frames: List[np.ndarray] = [] self.frames: Dict[Union[str, int], np.ndarray] = {}
self.input_vid_global_names: List[str] = [] self.input_vid_global_names: List[str] = []
self.window_names: List[str] = [] self.window_names: List[str] = []
self.input_cams: List[str] = [] self.input_cams: List[str] = []
@ -117,71 +117,98 @@ class SubscriberWindows(object):
mousey = MouseEvent(event, x, y, flags, param) mousey = MouseEvent(event, x, y, flags, param)
window_commands.mouse_pub.publish(mousey) window_commands.mouse_pub.publish(mousey)
def display_frames(self, frames, win_num=0, ids=None): def display_frames(self, frames, win_num=0, prepend_name=""):
"""Display a list of frames on multiple windows.""" """Display a list of frames on multiple windows."""
if isinstance(frames, Exception): if isinstance(frames, Exception):
raise frames raise frames
for f in range(len(frames)): if isinstance(frames, dict):
# detect nested: for f_name, f in frames.items():
if ( for i in range(len(f)):
isinstance(frames[f], (list, tuple)) # detect nested:
or frames[f].dtype.num == 17 if (
or ( isinstance(f[i], (list, tuple))
len(frames[f].shape) != 2 or f[i].dtype.num == 17
and (len(frames[f].shape) != 3 or frames[f].shape[-1] != 3) or (
) len(f[i].shape) != 2
): and (len(f[i].shape) != 3 or f[i].shape[-1] != 3)
win_num = self.display_frames(frames[f], win_num, ids) )
else: ):
if len(self.window_names) <= win_num: win_num = self.display_frames(
self.add_window(str(win_num)) f[i], win_num, prepend_name=f"{f_name} - "
cv2.imshow( )
self.window_names[win_num] + " (press ESC to quit)", frames[f] else:
) if len(self.window_names) <= win_num:
win_num += 1 self.add_window(f"{prepend_name}{win_num}")
cv2.imshow(
self.window_names[win_num] + " (press ESC to quit)", f[i]
)
win_num += 1
else:
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) != 2
and (len(frames[f].shape) != 3 or frames[f].shape[-1] != 3)
)
):
win_num = self.display_frames(frames[f], win_num, prepend_name)
else:
if len(self.window_names) <= win_num:
self.add_window(f"{prepend_name} {win_num}")
cv2.imshow(
self.window_names[win_num] + " (press ESC to quit)", frames[f]
)
win_num += 1
return win_num return win_num
def __check_too_many_channels(self): def __check_too_many_channels(self):
for f in range(len(self.frames)): for f_name, f in self.frames.items():
if isinstance(self.frames[f], Exception): for i in range(len(f)):
raise self.frames[f] if isinstance(f[i], Exception):
if ( raise f[i]
isinstance(self.frames[f], np.ndarray) if (
and self.frames[f].shape[-1] not in [1, 3] isinstance(f[i], np.ndarray)
and len(self.frames[f].shape) != 2 and f[i].shape[-1] not in [1, 3]
): and len(f[i].shape) != 2
print( ):
f"Too many channels in output. (Got {self.frames[f].shape[-1]} instead of 1 or 3.) " print(
f"Frame selection callback added." f"Too many channels in output. (Got {f[i].shape[-1]} instead of 1 or 3.) "
) f"Frame selection callback added."
print( )
"Ctrl+scroll to change first channel.\n" print(
"Shift+scroll to change second channel.\n" "Ctrl+scroll to change first channel.\n"
"Alt+scroll to change third channel." "Shift+scroll to change second channel.\n"
) "Alt+scroll to change third channel."
sel = SelectChannels() )
sel.enable_mouse_control() sel = SelectChannels()
sel.mouse_print_channels = True sel.enable_mouse_control()
self.callbacks.append(sel) sel.mouse_print_channels = True
for fr in range(len(self.frames)): self.callbacks.append(sel)
self.frames[fr] = self.callbacks[-1](self.frames[fr]) for fr in range(len(f)):
break f[fr] = self.callbacks[-1](f[fr])
break
def update_frames(self): def update_frames(self):
"""Update the windows with the newest data for all frames.""" """Update the windows with the newest data for all frames."""
self.frames = [] self.frames = {}
for i in range(len(self.input_vid_global_names)): for i in range(len(self.input_vid_global_names)):
if self.input_vid_global_names[i] in self.FRAME_DICT and not isinstance( if self.input_vid_global_names[i] in self.FRAME_DICT and not isinstance(
self.FRAME_DICT[self.input_vid_global_names[i]], NoData self.FRAME_DICT[self.input_vid_global_names[i]], NoData
): ):
self.frames.append(self.FRAME_DICT[self.input_vid_global_names[i]]) if self.input_vid_global_names[i] not in self.frames.keys():
if isinstance(self.frames, np.ndarray) and len(self.frames.shape) <= 3: self.frames[self.input_vid_global_names[i]] = []
self.frames = [self.frames] self.frames[self.input_vid_global_names[i]].append(
self.FRAME_DICT[self.input_vid_global_names[i]]
)
if len(self.callbacks) > 0: if len(self.callbacks) > 0:
for c in self.callbacks: for c in self.callbacks:
frame = c(self.frames[-1]) frame = c(self.frames[self.input_vid_global_names[i]][-1])
if frame is not None: if frame is not None:
self.frames[-1] = frame self.frames[self.input_vid_global_names[i]][-1] = frame
if not self.silent: if not self.silent:
self.__check_too_many_channels() self.__check_too_many_channels()
self.FRAME_DICT[self.input_vid_global_names[i]] = NoData() self.FRAME_DICT[self.input_vid_global_names[i]] = NoData()

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = 'displayarray' name = 'displayarray'
version = '0.7.5' version = '1.0.0'
description = 'Tool for displaying numpy arrays.' description = 'Tool for displaying numpy arrays.'
authors = ['SimLeek <simulator.leek@gmail.com>'] authors = ['SimLeek <simulator.leek@gmail.com>']
license = 'MIT' license = 'MIT'

View File

@ -193,7 +193,7 @@ def test_update_frames():
sw.update_frames() sw.update_frames()
assert sw.frames == [frame] assert sw.frames == {"0": [frame]}
mock_imshow.assert_called_once_with("displayarray (press ESC to quit)", frame) mock_imshow.assert_called_once_with("displayarray (press ESC to quit)", frame)
@ -219,7 +219,7 @@ def test_update_frames_callback():
sw.update_frames() sw.update_frames()
assert sw.frames == [frame3, frame3] assert sw.frames == {"0": [frame3], "1": [frame3]}
assert np.all(cb.mock_calls[0].args[0] == frame) assert np.all(cb.mock_calls[0].args[0] == frame)
assert np.all(cb2.mock_calls[0].args[0] == frame2) assert np.all(cb2.mock_calls[0].args[0] == frame2)
mock_imshow.assert_has_calls( mock_imshow.assert_has_calls(
@ -260,7 +260,7 @@ def test_update_frames_too_many_channels():
assert isinstance(sw.callbacks[-1], SelectChannels) assert isinstance(sw.callbacks[-1], SelectChannels)
assert sw.callbacks[-1].mouse_control is not None assert sw.callbacks[-1].mouse_control is not None
assert sw.callbacks[-1].mouse_print_channels is True assert sw.callbacks[-1].mouse_print_channels is True
assert sw.frames[0].shape[-1] == 3 assert sw.frames["0"][0].shape[-1] == 3
def test_update_frames_nested(): def test_update_frames_nested():
@ -275,47 +275,47 @@ def test_update_frames_nested():
sw.update_frames() sw.update_frames()
assert np.all(sw.frames[0] == np.ones((20, 100, 100, 3))) assert np.all(sw.frames["0"][0] == np.ones((20, 100, 100, 3)))
assert len(sw.frames) == 1 assert len(sw.frames) == 1
assert mock_imshow.mock_calls[0].args[0] == "displayarray (press ESC to quit)" assert mock_imshow.mock_calls[0].args[0] == "displayarray (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[0].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[0].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[1].args[0] == "1 (press ESC to quit)" assert mock_imshow.mock_calls[1].args[0] == "0 - 1 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[1].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[1].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[2].args[0] == "2 (press ESC to quit)" assert mock_imshow.mock_calls[2].args[0] == "0 - 2 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[2].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[2].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[3].args[0] == "3 (press ESC to quit)" assert mock_imshow.mock_calls[3].args[0] == "0 - 3 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[3].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[3].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[4].args[0] == "4 (press ESC to quit)" assert mock_imshow.mock_calls[4].args[0] == "0 - 4 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[4].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[4].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[5].args[0] == "5 (press ESC to quit)" assert mock_imshow.mock_calls[5].args[0] == "0 - 5 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[5].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[5].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[6].args[0] == "6 (press ESC to quit)" assert mock_imshow.mock_calls[6].args[0] == "0 - 6 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[6].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[6].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[7].args[0] == "7 (press ESC to quit)" assert mock_imshow.mock_calls[7].args[0] == "0 - 7 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[7].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[7].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[8].args[0] == "8 (press ESC to quit)" assert mock_imshow.mock_calls[8].args[0] == "0 - 8 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[8].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[8].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[9].args[0] == "9 (press ESC to quit)" assert mock_imshow.mock_calls[9].args[0] == "0 - 9 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[9].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[9].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[10].args[0] == "10 (press ESC to quit)" assert mock_imshow.mock_calls[10].args[0] == "0 - 10 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[10].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[10].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[11].args[0] == "11 (press ESC to quit)" assert mock_imshow.mock_calls[11].args[0] == "0 - 11 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[11].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[11].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[12].args[0] == "12 (press ESC to quit)" assert mock_imshow.mock_calls[12].args[0] == "0 - 12 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[12].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[12].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[13].args[0] == "13 (press ESC to quit)" assert mock_imshow.mock_calls[13].args[0] == "0 - 13 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[13].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[13].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[14].args[0] == "14 (press ESC to quit)" assert mock_imshow.mock_calls[14].args[0] == "0 - 14 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[14].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[14].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[15].args[0] == "15 (press ESC to quit)" assert mock_imshow.mock_calls[15].args[0] == "0 - 15 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[15].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[15].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[16].args[0] == "16 (press ESC to quit)" assert mock_imshow.mock_calls[16].args[0] == "0 - 16 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[16].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[16].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[17].args[0] == "17 (press ESC to quit)" assert mock_imshow.mock_calls[17].args[0] == "0 - 17 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[17].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[17].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[18].args[0] == "18 (press ESC to quit)" assert mock_imshow.mock_calls[18].args[0] == "0 - 18 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[18].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[18].args[1] == np.ones((100, 100, 3)))
assert mock_imshow.mock_calls[19].args[0] == "19 (press ESC to quit)" assert mock_imshow.mock_calls[19].args[0] == "0 - 19 (press ESC to quit)"
assert np.all(mock_imshow.mock_calls[19].args[1] == np.ones((100, 100, 3))) assert np.all(mock_imshow.mock_calls[19].args[1] == np.ones((100, 100, 3)))