Commit 2a46b1d1 authored by Thomas Dowrick's avatar Thomas Dowrick
Browse files

Start refactoring viewers to reduce duplication of code

parent 6c7ba233
Pipeline #1905 failed with stages
in 70 minutes and 31 seconds
......@@ -55,6 +55,42 @@ class DuplicateOverlayWindow(OverlayOnVideoFeedCropRecord):
self.vtk_overlay_window._RenderWindow.Render()
def on_record_start(self):
""" Don't want to call the base class version, so override."""
pass
def save_scene_to_file(self):
""" Don't want to call the base class version, so override."""
pass
def on_record_stop(self):
""" Don't want to call the base class version, so override."""
pass
def set_roi(self):
""" Don't want to call the base class version, so override."""
pass
class BlankFeed:
def on_record_start(self):
""" Don't want to call the base class version, so override."""
pass
def save_scene_to_file(self):
""" Don't want to call the base class version, so override."""
pass
def on_record_stop(self):
""" Don't want to call the base class version, so override."""
pass
def set_roi(self):
""" Don't want to call the base class version, so override."""
pass
def add_vtk_overlay(self):
""" Don't want to call the base class version, so override."""
pass
class MonoViewer(QtWidgets.QWidget):
"""
......@@ -65,18 +101,22 @@ class MonoViewer(QtWidgets.QWidget):
super().__init__()
LOGGER.info("Creating Mono Viewer")
self.overlay_window = OverlayOnVideoFeedCropRecord(video_source)
self.left_view = OverlayOnVideoFeedCropRecord(video_source)
self.right_view = None
self.UI = UI(self.left_view)
self.UI = UI(self.overlay_window)
self.auto_cropper = AutoCropBlackBorder(threshold = 50)
self.autocrop_timer = QTimer()
self.autocrop_timer.timeout.connect(self.update_autocrop)
self.setup_UI_callbacks()
def setup_UI_callbacks(self):
self.UI.screenshot_button.clicked.connect(self.on_screenshot_clicked)
self.UI.record_button.clicked.connect(self.on_record_start_clicked)
self.UI.crop_button.clicked.connect(self.on_crop_clicked)
self.UI.autocrop_button.clicked.connect(self.on_autocrop_started)
self.auto_cropper = AutoCropBlackBorder(threshold = 75)
self.autocrop_timer = QTimer()
self.autocrop_timer.timeout.connect(self.update_autocrop)
def add_vtk_models(self, models):
"""
Add vtk model overlays to the window
......@@ -87,30 +127,30 @@ class MonoViewer(QtWidgets.QWidget):
def start(self):
""" Start the viewer. """
self.overlay_window.start()
self.left_view.start()
def on_screenshot_clicked(self):
""" Save a screenshot to disk, using date and time as filename """
fname = datetime.datetime.now().strftime("%Y-%m-%d.%H-%M-%S") + '.png'
self.overlay_window.vtk_overlay_window.save_scene_to_file(fname)
self.left_view.vtk_overlay_window.save_scene_to_file(fname)
def on_record_start_clicked(self):
""" Start recording a video using current time as filename """
self.UI.record_button.setText("Stop recording")
self.UI.record_button.clicked.disconnect()
self.UI.record_button.clicked.connect(self.on_record_stop_clicked)
self.overlay_window.on_record_start()
self.left_view.on_record_start()
def on_record_stop_clicked(self):
""" Stop recording data to file and restore button settings. """
self.overlay_window.on_record_stop()
self.left_view.on_record_stop()
self.UI.record_button.setText("Record video")
self.UI.record_button.clicked.disconnect()
self.UI.record_button.clicked.connect(self.on_record_start_clicked)
def on_crop_clicked(self):
""" Crop the incoming video stream using ImageCropper. """
self.overlay_window.set_roi()
self.left_view.set_roi()
def on_autocrop_started(self):
""" Start auto cropping. """
......@@ -125,13 +165,13 @@ class MonoViewer(QtWidgets.QWidget):
self.UI.autocrop_button.clicked.disconnect()
self.UI.autocrop_button.clicked.connect(self.on_autocrop_started)
self.autocrop_timer.stop()
self.overlay_window.roi = None
self.left_view.roi = None
def update_autocrop(self):
""" Automatically crop the incoming video stream using AutoCropper.
"""
roi = self.auto_cropper.get_roi(self.overlay_window.img)
self.overlay_window.roi = roi
roi = self.auto_cropper.get_roi(self.left_view.img)
self.left_view.roi = roi
class StereoViewerBase(QtWidgets.QWidget):
......@@ -152,14 +192,14 @@ class StereoViewerBase(QtWidgets.QWidget):
def setup_widgets(self):
""" Sync the cameras between the widgets,
and setup Qt output signal. """
self.UI = UI(self.ui_window)
self.UI = UI(self.ui_view)
self.UI.screenshot_button.clicked.connect(self.on_screenshot_clicked)
self.UI.record_button.clicked.connect(self.on_record_start_clicked)
self.UI.crop_button.clicked.connect(self.on_crop)
self.left_overlay = self.left_view.vtk_overlay_window
self.right_overlay = self.right_view.vtk_overlay_window
self.ui_overlay = self.ui_window.vtk_overlay_window
self.ui_overlay = self.ui_view.vtk_overlay_window
self.sync_camera_view_between_windows()
......@@ -258,7 +298,7 @@ class StereoViewerBase(QtWidgets.QWidget):
self.left_view.start()
self.right_view.start()
self.ui_window.start()
self.ui_view.start()
def run_before_quit(self):
"""
......@@ -268,7 +308,7 @@ class StereoViewerBase(QtWidgets.QWidget):
self.left_view.stop()
self.right_view.stop()
self.ui_window.stop()
self.ui_view.stop()
def on_screenshot_clicked(self):
""" Save a screenshot to disk, using date and time as filename """
......@@ -292,6 +332,10 @@ class StereoViewerBase(QtWidgets.QWidget):
self.left_view.output_filename = fname_left
self.left_view.on_record_start()
fname_right = self.video_fname_base + '-RIGHT.avi'
self.right_view.output_filename = fname_right
self.right_view.on_record_start()
self.UI.record_button.setText("Stop recording")
self.UI.record_button.clicked.disconnect()
self.UI.record_button.clicked.connect(self.on_record_stop_clicked)
......@@ -299,12 +343,15 @@ class StereoViewerBase(QtWidgets.QWidget):
def on_record_stop_clicked(self):
""" Stop recording data to file and restore button settings. """
self.left_view.on_record_stop()
self.right_view.on_record_stop()
self.UI.record_button.setText("Record video")
self.UI.record_button.clicked.disconnect()
self.UI.record_button.clicked.connect(self.on_record_start_clicked)
def on_crop(self):
self.left_view.set_roi()
self.right_view.roi = self.left_view.roi
class MockStereoViewer(StereoViewerBase):
"""
......@@ -324,13 +371,11 @@ class MockStereoViewer(StereoViewerBase):
self.right_view = DuplicateOverlayWindow()
self.right_view.set_source_window(self.left_view)
self.ui_window = DuplicateOverlayWindow()
self.ui_window.set_source_window(self.left_view)
self.ui_view = DuplicateOverlayWindow()
self.ui_view.set_source_window(self.left_view)
self.setup_widgets()
class StereoViewer(StereoViewerBase):
"""Stereo viewer, creates an overlay window for each
video input.
......@@ -348,8 +393,8 @@ class StereoViewer(StereoViewerBase):
self.left_view = OverlayOnVideoFeedCropRecord(left_source)
self.right_view = OverlayOnVideoFeedCropRecord(right_source)
self.ui_window = DuplicateOverlayWindow()
self.ui_window.set_source_window(self.left_view)
self.ui_view = DuplicateOverlayWindow()
self.ui_view.set_source_window(self.left_view)
self.setup_widgets()
......
......@@ -96,26 +96,3 @@ class AutoCropBlackBorder:
self.roi.append((end_x, end_y))
return self.roi
if __name__ == "__main__":
input_file = 'tests/data/davinci_xi_generated_video.avi'
vid = cv2.VideoCapture(input_file)
crop = AutoCropBlackBorder()
crop.min_size = 50
crop.threshold = 10
while vid.isOpened():
ret, img = vid.read()
cv2.imshow('orig', img)
roi = crop.get_roi(img)
start_x, start_y = roi[0]
end_x, end_y = roi[1]
cv2.imshow('crop', img[start_y:end_y, start_x:end_x, :])
cv2.waitKey(10)
......@@ -4,25 +4,6 @@ import pytest
import numpy as np
from sksurgerydavinci.widgets import Viewers
from sksurgeryutils.common_overlay_apps import OverlayOnVideoFeed
# pyint:disable=line-too-long
# # GUI tests causing error on Linux CI-machine.
# in_gitlab_ci = str(os.environ.get('GITLAB_CI'))
# print("Gitlab_CI" + in_gitlab_ci)
# if sys.platform == "linux" and in_gitlab_ci:
# pytest.skip("skipping GUI tests on linux CI", allow_module_level=True)
@pytest.fixture(scope="module")
def video_file_source():
""" Provide video file for subsequent tests"""
video_filename = 'tests/data/test_video.avi'
return video_filename
@pytest.fixture(scope="module")
def mock_stereo_widget(video_file_source):
""" Provide video file for subsequent tests"""
return mock_stereo
def test_mock_stereo_cameras_are_synced(qtbot):
......
......@@ -33,36 +33,36 @@ def set_central_screen(img, size):
return roi
# def test_roi_all_black_border():
# """ Generated image has black border, then roi e.g.
# """
# width, height = 1920, 1080
# crop = AutoCropBlackBorder()
def test_roi_all_black_border():
""" Generated image has black border, then roi e.g.
"""
width, height = 1920, 1080
crop = AutoCropBlackBorder()
# for size in [100, 101, 200, 500, 1000, 1001]:
# img = np.zeros((height, width, 3), dtype=np.uint8)
for size in [100, 101, 200, 500, 1000, 1001]:
img = np.zeros((height, width, 3), dtype=np.uint8)
# expected_roi = set_central_screen(img, size)
# calculated_roi = crop.get_roi(img)
expected_roi = set_central_screen(img, size)
calculated_roi = crop.get_roi(img)
# assert expected_roi == calculated_roi
assert expected_roi == calculated_roi
# def test_roi_black_border_first_row_white():
# """ The first row on the DaVinci Xi stream is white (for some reason)
# so make sure we can handle this case.
# """
def test_roi_black_border_first_row_white():
""" The first row on the DaVinci Xi stream is white (for some reason)
so make sure we can handle this case.
"""
# width, height = 1920, 1080
# crop = AutoCropBlackBorder()
width, height = 1920, 1080
crop = AutoCropBlackBorder()
# for size in [100, 101, 200, 500, 1000, 1001]:
# img = np.zeros((height, width, 3), dtype=np.uint8)
# img[0,:,:] = 255
for size in [100, 101, 200, 500, 1000, 1001]:
img = np.zeros((height, width, 3), dtype=np.uint8)
img[0,:,:] = 255
# expected_roi = set_central_screen(img, size)
# calculated_roi = crop.get_roi(img)
expected_roi = set_central_screen(img, size)
calculated_roi = crop.get_roi(img)
# assert expected_roi == calculated_roi
assert expected_roi == calculated_roi
def test_no_border():
......@@ -104,21 +104,27 @@ def test_no_border_top_left():
calculated_roi = crop.get_roi(img)
assert expected_roi == calculated_roi
def test_on_realistic_video():
# Test using video which replicates the actual video stream
# of the DaVinci Xi.
# Video generated using tests/data/gen_xi_video.py
input_file = 'tests/data/davinci_xi_generated_video.avi'
vid = cv2.VideoCapture(input_file)
crop = AutoCropBlackBorder()
crop.min_size = 50
crop.threshold = 10
for i in range(100):
size = 2 * (100 + i)
ret, img = vid.read()
# start_x, start_y = roi[0]
# end_x, end_y = roi[1]
# print(f"size: {size} w: {end_x-start_x}, h: {end_y-start_y}")
# cv2.imshow('Clipped', img[start_y:end_y,start_x:end_x,:])
# cv2.waitKey(500)
# img[0,:,:] = 255
# roi = crop.get_roi(img)
# start_x, start_y = roi[0]
# end_x, end_y = roi[1]
# print(f"size: {size} w: {end_x-start_x}, h: {end_y-start_y}")
roi = crop.get_roi(img)
start_x, start_y = roi[0]
end_x, end_y = roi[1]
# cv2.imshow('Clipped', img[start_y:end_y,start_x:end_x,:])
# cv2.waitKey(500)
assert (end_x - start_x) == size
assert (end_y - start_y) == size
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment