Skip to content

Commit

Permalink
Merge pull request #48 from SciKit-Surgery/46-use-headless
Browse files Browse the repository at this point in the history
46 use headless
  • Loading branch information
thompson318 committed Jul 5, 2022
2 parents 5334363 + a8d1edc commit 03aae88
Show file tree
Hide file tree
Showing 110 changed files with 3,931 additions and 123 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -9,20 +9,29 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-ver: [3.7, 3.8]
python-ver: [3.7]
experimental: [false]
include:
- python-ver: 3.8
os: ubuntu-latest
experimental: false
- python-ver: 3.8
os: windows-latest
experimental: true
- python-ver: 3.8
os: macos-latest
experimental: false
- python-ver: 3.9
os: ubuntu-latest
experimental: true

- python-ver: 3.9
os: windows-latest
experimental: true
- python-ver: 3.9
os: macos-latest
experimental: true


runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
timeout-minutes: 10
Expand Down
17 changes: 17 additions & 0 deletions config/.gitignore
@@ -0,0 +1,17 @@
# Pycharm
/.idea

# Generated files
.tox
.coverage
*.pyc
.pytest_cache/

# PyInstaller
build/
dist/
model2camera.spec

# Mac Finder:
.DS_Store

8 changes: 8 additions & 0 deletions config/video_chessboard_conf.json
@@ -0,0 +1,8 @@
{
"method": "chessboard",
"corners": [14, 10],
"square size in mm": 6,
"minimum number of views": 5,
"keypress delay in ms": 1000,
"sample frequency" : 1
}
2 changes: 1 addition & 1 deletion requirements-dev.txt
Expand Up @@ -8,7 +8,7 @@ coverage
mock
pyfakefs
parameterized
pylint
pylint<2.14
sphinx
sphinx_rtd_theme
pyinstaller
Expand Down
11 changes: 6 additions & 5 deletions requirements.txt
Expand Up @@ -4,9 +4,10 @@
# doc/requirements.rst
six>=1.10
numpy>=1.11
opencv-contrib-python-headless>=4.1.1.26
PySide2<5.15.0
opencv-contrib-python-headless>=4.1.1.26,<4.6
scikit-surgerycore>=0.1.7
scikit-surgeryimage>=0.2.0
scikit-surgeryvtk>=0.19.1
scikit-surgeryarucotracker>=0.0.4
scikit-surgeryimage>=0.10.1
scikit-surgeryvtk>=1.0.6
scikit-surgeryarucotracker>=0.2.7
scikit-surgerycalibration>=0.2.1
PySide2>=5.12.0
12 changes: 7 additions & 5 deletions setup.py
Expand Up @@ -14,7 +14,7 @@
name='scikit-surgeryutils',
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
description='scikit-surgeryutils - Tests/demos utilities, based around opencv-contrib and PySide2',
description='scikit-surgeryutils - Tests/demos utilities, based around opencv-contrib-python-headless and PySide2',
long_description=long_description,
long_description_content_type='text/x-rst',
url='https://github.com/SciKit-Surgery/scikit-surgeryutils',
Expand Down Expand Up @@ -56,10 +56,10 @@
'opencv-contrib-python-headless>=4.1.1.26',
'PySide2<5.15.0',
'scikit-surgerycore>=0.1.7',
'scikit-surgeryimage>=0.2.0',
'scikit-surgeryvtk>=0.19.1',
'scikit-surgeryarucotracker>=0.0.4'

'scikit-surgeryimage>=0.10.1',
'scikit-surgeryvtk>=1.0.6',
'scikit-surgeryarucotracker>=0.2.7',
'scikit-surgerycalibration>=0.2.1'
],

entry_points={
Expand All @@ -71,6 +71,8 @@
'sksurgeryreslice=sksurgeryutils.ui.sksurgeryreslice_command_line:main',
'sksurgerytextoverlay=sksurgeryutils.ui.sksurgerytextoverlay_command_line:main',
'sksurgerytransformpolydata=sksurgeryutils.ui.sksurgeryrendermodelslikecamera_command_line:main',
'sksurgeryvideocalibration=sksurgeryutils.ui.sksurgeryvideocalibration_command_line:main',
'sksurgeryvideocalibrationchecker=sksurgeryutils.ui.sksurgeryvideocalibrationchecker_command_line:main',
],
},
)
124 changes: 51 additions & 73 deletions sksurgeryutils/common_overlay_apps.py
@@ -1,44 +1,70 @@
"""Common use cases for vtk_overlay_window"""
# coding=utf-8

""" Common use cases for vtk_overlay_window """

#pylint: disable=no-member, no-name-in-module, protected-access
# coding=utf-8

import datetime
import logging
import cv2

from PySide2.QtWidgets import QWidget, QHBoxLayout
from PySide2.QtCore import QTimer
from sksurgeryimage.acquire.video_source import TimestampedVideoSource
from sksurgeryimage.acquire.video_writer import TimestampedVideoWriter

from sksurgeryvtk.widgets.vtk_overlay_window import VTKOverlayWindow
from sksurgeryvtk.models.vtk_surface_model_directory_loader \
import VTKSurfaceModelDirectoryLoader

class OverlayBaseApp():

class OverlayBaseWidget(QWidget):
"""
Base class for applications that use vtk_overlay_window.
The update() method should be implemented in the child
class.
:param video_source: OpenCV compatible video source (int or filename)
:param dims: size of video feed
"""
def __init__(self, video_source, dims=None):
super().__init__()

self.layout = QHBoxLayout(self)
self.layout.setContentsMargins(0, 0, 0, 0)
self.layout.setSpacing(0)

self.vtk_overlay_window = VTKOverlayWindow()
self.layout.addWidget(self.vtk_overlay_window)

self.video_source = TimestampedVideoSource(video_source, dims)

self.timer = QTimer()
self.timer.timeout.connect(self.update_view)

self.update_rate = 30
self.img = None
self.timer = None
self.save_frame = None

def start(self):
"""Show the overlay widget and
set a timer running"""
self.vtk_overlay_window.show()

self.timer = QTimer()
self.timer.timeout.connect(self.update)
"""
Starts the timer, which repeatedly triggers the update_view() method.
"""
self.timer.start(1000.0 / self.update_rate)

def stop(self):
"""
Stops the timer.
"""
self.timer.stop()

def terminate(self):
"""
Make sure that the VTK Interactor terminates nicely, otherwise
it can throw some error messages, depending on the usage.
"""
self.vtk_overlay_window._RenderWindow.Finalize()
self.vtk_overlay_window.TerminateApp()

def add_vtk_models_from_dir(self, directory):
"""
Add VTK models to the foreground.
Expand All @@ -47,34 +73,28 @@ def add_vtk_models_from_dir(self, directory):
model_loader = VTKSurfaceModelDirectoryLoader(directory)
self.vtk_overlay_window.add_vtk_models(model_loader.models)

def update(self):
def update_view(self):
""" Update the scene background and/or foreground.
Should be implemented by sub class """

raise NotImplementedError('Should have implemented this method.')

def stop(self):
"""
Make sure that the VTK Interactor terminates nicely, otherwise
it can throw some error messages, depending on the usage.
"""
self.vtk_overlay_window._RenderWindow.Finalize()
self.vtk_overlay_window.TerminateApp()

class OverlayOnVideoFeed(OverlayBaseApp):
class OverlayOnVideoFeed(OverlayBaseWidget):
"""
Uses the acquired video feed as the background image,
with no additional processing.
"""

def update(self):
""" Get the next frame of input and display it. """
def update_view(self):
"""
Get the next frame of input and display it.
"""
_, self.img = self.video_source.read()
self.vtk_overlay_window.set_video_image(self.img)
self.vtk_overlay_window._RenderWindow.Render()
self.vtk_overlay_window.Render()


class OverlayOnVideoFeedCropRecord(OverlayBaseApp):
class OverlayOnVideoFeedCropRecord(OverlayBaseWidget):
""" Add cropping of the incoming video feed, and the ability to
record the vtk_overlay_window.
Expand All @@ -89,14 +109,15 @@ def __init__(self, video_source, output_filename=None, dims=None):
self.output_filename = output_filename
self.video_writer = None

def update(self):
""" Get the next frame of input, crop and/or
write to file (if either enabled). """
def update_view(self):
"""
Get the next frame of input, crop and/or
write to file (if either enabled).
"""
_, self.img = self.video_source.read()

self.vtk_overlay_window.set_video_image(self.img)

self.vtk_overlay_window._RenderWindow.Render()
self.vtk_overlay_window.Render()

if self.save_frame:
output_frame = self.get_output_frame()
Expand Down Expand Up @@ -144,46 +165,3 @@ def on_record_stop(self):
self.save_frame = False
self.video_writer.close()
logging.debug("Recording stopped.")


class DuplicateOverlayWindow(OverlayOnVideoFeedCropRecord):
"""
Set the background of vtk_overlay_window to duplicate
that of another vtk_overlay_window.
Example usage:
video_source = 0
source_window = OverlayOnVideoFeedCropRecord(video_source)
duplicate_window = DuplicateOverlayWindow()
duplicate_window.set_source_window(source_window)
"""
def __init__(self):

#pylint: disable=super-init-not-called
self.vtk_overlay_window = VTKOverlayWindow()
self.update_rate = 30
self.img = None
self.timer = None
self.source_window = None

def set_source_window(self, source_window):
""" Set the source window.
:param source_window: The window that contains the image to copy. """
self.source_window = source_window

def update(self):
""" Update the frame with a new background image."""

self.img = self.source_window.vtk_overlay_window.input
self.vtk_overlay_window.set_video_image(self.img)

self.vtk_overlay_window._RenderWindow.Render()

def on_record_start(self):
""" Don't want to call the base class version, so override."""


def on_record_stop(self):
""" Don't want to call the base class version, so override."""
1 change: 1 addition & 0 deletions sksurgeryutils/ui/sksurgeryreslice_demo.py
Expand Up @@ -5,6 +5,7 @@

from sksurgeryarucotracker.arucotracker import ArUcoTracker


def run_demo(tracked, dicom_dir):

""" Demo """
Expand Down
5 changes: 4 additions & 1 deletion sksurgeryutils/ui/sksurgerytextoverlay_demo.py
Expand Up @@ -12,7 +12,9 @@

logging.basicConfig(level=logging.INFO)
LOGGER = logging.getLogger(__name__)
#pylint:disable=line-too-long, invalid-name, unused-argument


# pylint:disable=line-too-long, invalid-name, unused-argument
class TextOverlayDemo(common_overlay_apps.OverlayOnVideoFeed):
""" Demo app, to show text overlay"""
def __init__(self, video_source):
Expand Down Expand Up @@ -50,6 +52,7 @@ def mouse_click_callback(self, obj, ev):
vtk_text.set_parent_window(self.vtk_overlay_window)
self.vtk_overlay_window.add_vtk_actor(vtk_text.text_actor, 2)


def run_demo():
""" Run demo """
app = QApplication([])
Expand Down
3 changes: 2 additions & 1 deletion sksurgeryutils/ui/sksurgerytransformpolydata_demo.py
Expand Up @@ -9,7 +9,8 @@
import sksurgeryvtk.utils.matrix_utils as mu
import sksurgeryvtk.models.vtk_surface_model as sm

#pylint:disable=no-member
# pylint:disable=no-member


def run_demo(input_file,
output_file,
Expand Down

0 comments on commit 03aae88

Please sign in to comment.