Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
WEISS
Software Repositories
SNAPPY
scikit-surgerydavinci
Commits
5da1ca3b
Commit
5da1ca3b
authored
Apr 04, 2019
by
Thomas Dowrick
Browse files
Finish refactoring
parent
b28e874d
Changes
2
Hide whitespace changes
Inline
Side-by-side
sksurgerydavinci/widgets/Viewers.py
View file @
5da1ca3b
...
...
@@ -46,9 +46,11 @@ class DuplicateOverlayWindow(OverlayOnVideoFeedCropRecord):
if
self
.
source_window
.
roi
:
start_x
,
start_y
=
self
.
source_window
.
roi
[
0
]
end_x
,
end_y
=
self
.
source_window
.
roi
[
1
]
self
.
vtk_overlay_window
.
set_video_image
(
self
.
source_window
.
img
[
start_y
:
end_y
,
start_x
:
end_x
,
:])
self
.
vtk_overlay_window
.
\
set_video_image
(
self
.
source_window
.
img
[
start_y
:
end_y
,
start_x
:
end_x
,
:])
else
:
self
.
vtk_overlay_window
.
set_video_image
(
self
.
source_window
.
img
)
...
...
@@ -57,95 +59,76 @@ class DuplicateOverlayWindow(OverlayOnVideoFeedCropRecord):
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
class
FakeOverlayOnVideoFeed
:
""" Implement empty methods to replicate OverlayOnVideoFeed. """
def
start
(
self
):
""" Intentionally Blank. """
def
stop
(
self
):
""" Intentionally Blank. """
def
on_record_start
(
self
):
""" Intentionally Blank. """
def
on_record_stop
(
self
):
""" Don't want to call the base class version, so override."""
pass
""" Intentionally Blank. """
def
set_roi
(
self
):
""" Don't want to call the base class version, so override."""
pass
""" Intentionally Blank. """
def
add_vtk_models
(
self
,
models
):
pass
def
add_vtk_overlay
(
self
):
""" Don't want to call the base class version, so override."""
pass
class
FakeVTKOverlayWindow
:
""" Implement empty methods to replicate VTKOverlayWindow. """
def
save_scene_to_file
(
self
,
fname
):
""" Intentionally Blank. """
def
get_foreground_camera
(
self
):
pass
""" Intentionally Blank. """
def
set_foreground_camera
(
self
,
camera
):
""" Blank method. """
pass
""" Intentionally Blank. """
def
set_screen
(
self
):
""" Blank method. """
pass
""" Intentionally Blank. """
def
set_geometry
(
self
):
""" Blank. """
pass
""" Intentionally Blank. """
def
start
(
self
):
pass
def
add_vtk_models
(
self
,
models
):
""" Intentionally Blank. """
def
stop
(
self
):
pass
class
StereoViewerBase
(
QtWidgets
.
QWidget
):
"""
Base class for StereoViewers.
Child classes implment the left/right/ui video feeds as appropriate.
"""
def
__init__
(
self
):
# Left/right stereo views and UI view.
# These are overridden in subclasses.
# Included here for clarity.
super
().
__init__
()
self
.
UI
=
BlankFeed
()
self
.
left_view
=
BlankFeed
()
self
.
right_view
=
BlankFeed
()
self
.
ui_view
=
BlankFeed
()
self
.
left_overlay
=
BlankFeed
()
self
.
right_overlay
=
BlankFeed
()
self
.
ui_overlay
=
BlankFeed
()
def
setup_widgets
(
self
):
""" Sync the cameras between the widgets,
and setup Qt output signal. """
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
.
UI
.
exit_signal
.
connect
(
self
.
run_before_quit
)
self
.
sync_camera_view_between_windows
()
self
.
auto_cropper
=
AutoCropBlackBorder
(
threshold
=
50
)
self
.
autocrop_timer
=
QTimer
()
self
.
autocrop_timer
.
timeout
.
connect
(
self
.
update_autocrop
)
self
.
UI
.
exit_signal
.
connect
(
self
.
run_before_quit
)
self
.
sync_camera_view_between_windows
(
)
def
sync_camera_view_between_windows
(
self
):
"""
...
...
@@ -202,7 +185,7 @@ class StereoViewerBase(QtWidgets.QWidget):
"""
Check if each widget has been placed on it's own screen.
:param screens: List of screen numbers corresponding to the screen
each widget is displayed on.
each widget is displayed on.
:type screens: list of ints
"""
...
...
@@ -254,8 +237,15 @@ class StereoViewerBase(QtWidgets.QWidget):
def
on_screenshot_clicked
(
self
):
""" Save a screenshot to disk, using date and time as filename """
fname_base
=
datetime
.
datetime
.
now
().
strftime
(
"%Y-%m-%d.%H-%M-%S"
)
fname_left
=
fname_base
+
'-LEFT.png'
fname_base
=
'outputs/'
\
+
datetime
.
datetime
.
now
().
strftime
(
"%Y-%m-%d.%H-%M-%S"
)
if
self
.
__class__
.
__name__
==
"MonoViewer"
:
fname_left
=
fname_base
+
'-MONO.png'
else
:
fname_left
=
fname_base
+
'-LEFT.png'
fname_right
=
fname_base
+
'-RIGHT.png'
self
.
left_overlay
.
save_scene_to_file
(
fname_left
)
...
...
@@ -267,14 +257,20 @@ class StereoViewerBase(QtWidgets.QWidget):
left.
The proper StereoViewer class extends this method to also record
the right view."""
self
.
video_
fname_base
=
'outputs/'
+
\
fname_base
=
'outputs/'
+
\
datetime
.
datetime
.
now
().
strftime
(
"%Y-%m-%d.%H-%M-%S"
)
fname_left
=
self
.
video_fname_base
+
'-LEFT.avi'
if
self
.
__class__
.
__name__
==
"MonoViewer"
:
fname_left
=
fname_base
+
'-MONO.avi'
else
:
fname_left
=
fname_base
+
'-LEFT.avi'
fname_right
=
fname_base
+
'-RIGHT.avi'
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
()
...
...
@@ -292,35 +288,10 @@ class StereoViewerBase(QtWidgets.QWidget):
self
.
UI
.
record_button
.
clicked
.
connect
(
self
.
on_record_start_clicked
)
def
on_crop_clicked
(
self
):
""" Set the ROI on the left view, and copy it to the right. """
self
.
left_view
.
set_roi
()
self
.
right_view
.
roi
=
self
.
left_view
.
roi
class
MonoViewer
(
StereoViewerBase
):
"""
Generates a VTK interactor UI with a video stream as background
:param video_source: OpenCV compatible video source (int or filename)
"""
def
__init__
(
self
,
video_source
):
super
().
__init__
()
LOGGER
.
info
(
"Creating Mono Viewer"
)
self
.
left_view
=
OverlayOnVideoFeedCropRecord
(
video_source
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
#TODO: Change this bit, don't really want ui_view diff from UI
self
.
UI
=
UI
(
self
.
left_view
)
self
.
auto_cropper
=
AutoCropBlackBorder
(
threshold
=
50
)
self
.
autocrop_timer
=
QTimer
()
self
.
autocrop_timer
.
timeout
.
connect
(
self
.
update_autocrop
)
# TODO: Move this to super class, then call super at end of this init
self
.
setup_widgets
()
def
setup_UI_callbacks
(
self
):
self
.
UI
.
autocrop_button
.
clicked
.
connect
(
self
.
on_autocrop_started
)
def
on_autocrop_started
(
self
):
""" Start auto cropping. """
self
.
UI
.
autocrop_button
.
setText
(
"Disable Auto Crop"
)
...
...
@@ -348,36 +319,52 @@ class MonoViewer(StereoViewerBase):
self
.
left_view
.
roi
=
roi
self
.
right_view
.
roi
=
roi
class
MonoViewer
(
StereoViewerBase
):
"""
Generates a VTK interactor UI with a single video stream as background.
:param video_source: OpenCV compatible video source (int or filename)
"""
def
__init__
(
self
,
video_source
):
LOGGER
.
info
(
"Creating Mono Viewer"
)
self
.
left_view
=
OverlayOnVideoFeedCropRecord
(
video_source
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
self
.
right_view
=
FakeOverlayOnVideoFeed
()
self
.
right_overlay
=
FakeVTKOverlayWindow
()
self
.
ui_view
=
FakeOverlayOnVideoFeed
()
self
.
ui_overlay
=
FakeVTKOverlayWindow
()
self
.
UI
=
UI
(
self
.
left_view
)
super
().
__init__
()
class
MockStereoViewer
(
StereoViewerBase
):
"""
Mock stereo viewer, duplicating a single
web
cam input
Mock stereo viewer, duplicating a single cam
era
input
to multiple screens.
:param video_source: OpenCV compatible video source (int or filename)
"""
def
__init__
(
self
,
video_source
):
super
().
__init__
()
LOGGER
.
info
(
"Creating Mock Stereo Viewwer"
)
#TODO: Move to superclass
self
.
left_view
=
OverlayOnVideoFeedCropRecord
(
video_source
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
self
.
right_view
=
DuplicateOverlayWindow
()
self
.
right_view
.
set_source_window
(
self
.
left_view
)
self
.
right_overlay
=
self
.
right_view
.
vtk_overlay_window
self
.
ui_view
=
DuplicateOverlayWindow
()
self
.
ui_view
.
set_source_window
(
self
.
left_view
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
self
.
right_overlay
=
self
.
right_view
.
vtk_overlay_window
self
.
ui_overlay
=
self
.
ui_view
.
vtk_overlay_window
self
.
UI
=
UI
(
self
.
ui_view
)
s
elf
.
setup_widgets
()
s
uper
().
__init__
()
class
StereoViewer
(
StereoViewerBase
):
"""Stereo viewer, creates an overlay window for each
...
...
@@ -389,21 +376,19 @@ class StereoViewer(StereoViewerBase):
def
__init__
(
self
,
left_source
,
right_source
):
super
().
__init__
()
LOGGER
.
info
(
"Creating Stereo Viewer"
)
self
.
left_view
=
OverlayOnVideoFeedCropRecord
(
left_source
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
self
.
right_view
=
OverlayOnVideoFeedCropRecord
(
right_source
)
self
.
right_overlay
=
self
.
right_view
.
vtk_overlay_window
self
.
ui_view
=
DuplicateOverlayWindow
()
self
.
ui_view
.
set_source_window
(
self
.
left_view
)
self
.
left_overlay
=
self
.
left_view
.
vtk_overlay_window
self
.
right_overlay
=
self
.
right_view
.
vtk_overlay_window
self
.
ui_overlay
=
self
.
ui_view
.
vtk_overlay_window
self
.
UI
=
UI
(
self
.
ui_view
)
self
.
setup_widgets
()
super
().
__init__
()
sksurgerydavinci/widgets/auto_cropping.py
View file @
5da1ca3b
import
numpy
as
np
import
cv2
import
time
#coding=utf-8
""" AutoCropper Module. """
from
sksurgeryimage.acquire.video_source
import
TimestampedVideoSource
import
numpy
as
np
class
AutoCropBlackBorder
:
...
...
@@ -31,10 +30,11 @@ class AutoCropBlackBorder:
""" Given a vector, skip any leading values that are > threshold,
then find the first contiguous range of values that are below the
threshold value.
If the whole vector is above the threshold, return the start/end indexes.
If the whole vector is above the threshold, return the start/end
indexes.
e.g.
[0 0 0 50 50 50 0 0 0 ] return 3, 5 - [50 50 50]
[25 25 0 0 25 25 25 0 0] returns 4, 7 [25 25 25] as the leading 25s are
skipped.
...
...
@@ -85,8 +85,8 @@ class AutoCropBlackBorder:
# Only use the red channel, otherwise we need to take the average along
# two dimensions, which is slow. This should be acceptable for the
# DaVinci.
col_mean
=
np
.
mean
(
img
[:,:,
1
],
axis
=
(
0
))
row_mean
=
np
.
mean
(
img
[:,:,
1
],
axis
=
(
1
))
col_mean
=
np
.
mean
(
img
[:,
:,
1
],
axis
=
(
0
))
row_mean
=
np
.
mean
(
img
[:,
:,
1
],
axis
=
(
1
))
start_y
,
end_y
=
self
.
get_bounds
(
row_mean
)
start_x
,
end_x
=
self
.
get_bounds
(
col_mean
)
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment