diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2835d51..a1b1c8c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,12 @@ jobs: python-ver: [3.7, 3.8] experimental: [false] exclude: - - os: macos-latest - python-ver: 3.6 + - os: windows-latest + python-ver: 3.8 include: + - python-ver: 3.8 + os: windows-latest + experimental: true - python-ver: 3.9 os: ubuntu-latest experimental: true diff --git a/README.rst b/README.rst index f249a86..2cd3109 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,8 @@ SciKit-Surgery Augmented Reality Tutorial :target: https://twitter.com/scikit_surgery?ref_src=twsrc%5Etfw :alt: Follow scikit_surgery on twitter -Author: Stephen Thompson +Author(s): Stephen Thompson. +Contributor(s): Miguel Xochicale, Mian Asbat Ahmad and Matt Clarkson. This is the SciKit-Surgery Augmented Reality Tutorial. It will teach you how to write an augmented reality application, showing a rendered model on top of a live video feed. diff --git a/doc/00_Introduction.rst b/doc/00_Introduction.rst index 5ca034a..a1c43e6 100644 --- a/doc/00_Introduction.rst +++ b/doc/00_Introduction.rst @@ -59,8 +59,42 @@ For the third part of the tutorial you'll also need SciKit-SurgeryArUcoTracker If you don't have Python installed, we recommend downloading an installer for your platform directly from `python.org`_. -You can also use a virtual environment to run the tutorial without altering your system's Python -installation, see our instructions for `virtual environments`_. +Virtual environments +~~~~~~~~~~~~ +Virtualenv, venv, conda or pyenv can be used to create virtual environments to manage python packages. +You can use conda env by installing conda for your OS (`conda_installation`_) and use the following yml file with all dependencies. +:: + ## Create scikit-surgerytutorial01VE.yml in your favorite location with the following content: + ## + ## scikit-surgerytutorial01VE.yml + ## + ## Some useful commands to manage your conda env: + ## LIST CONDA ENVS: conda list -n *VE # show list of installed packages + ## UPDATE CONDA: conda update -n base -c defaults conda + ## INSTALL CONDA EV: conda env create -f *VE.yml + ## UPDATE CONDA ENV: conda env update --file *VE.yml --prune + ## ACTIVATE CONDA ENV: conda activate *VE + ## REMOVE CONDA ENV: conda remove -n *VE --all + + name: scikit-surgerytutorial01VE + channels: + - defaults + - conda-forge #vtk; tox; + - anaconda #coverage; scipy; + dependencies: + - python=3.7 + - numpy>=1.17.4 + - vtk=8.1.2 + - tox>=3.26.0 + - pytest>=7.1.2 + - pylint>=2.14.5 + - pip>=22.2.2 + - pip: + - PySide2>=5.14.2.3 + - scikit-surgerycore>=0.1.7 + - scikit-surgeryutils>=1.2.0 + - scikit-surgeryarucotracker>=0.1.1 + - opencv-python-headless Step 2: You should now be able to follow the tutorial, using the code snippets contained herein. @@ -74,5 +108,4 @@ You should now be able to follow the tutorial, using the code snippets contained .. _`PySide2`: https://pypi.org/project/PySide2 .. _`OpenCV` : https://pypi.org/project/opencv-contrib-python .. _`VTK` : https://pypi.org/project/vtk -.. _`virtual environments` : https://weisslab.cs.ucl.ac.uk/WEISS/wiki/wikis/Creating-Python-Virtual-Environment-using-Anaconda/Minicoda-and-Virtualenv - +.. _`conda_installation` : https://conda.io/projects/conda/en/latest/user-guide/install/index.html diff --git a/doc/01_VTK_Overlay_App.rst b/doc/01_VTK_Overlay_App.rst index 664b264..2af4f0f 100644 --- a/doc/01_VTK_Overlay_App.rst +++ b/doc/01_VTK_Overlay_App.rst @@ -13,8 +13,8 @@ of a model, overlaid on live video from your webcam, something like this ... 00 - Simple overlay application ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using your favourite text editor or Python development environment, -create a new file called vtkoverlay_app.py or similar. +Using your favourite text editor or Python development environment (e.g., `pycharm`_, `vscode`_, etc), +create a new file called vtkoverlay_app.py or similar under a new directory applications or your preferred name. Start with some import statements @@ -22,23 +22,23 @@ Start with some import statements import sys from PySide2.QtWidgets import QApplication - from sksurgeryutils.common_overlay_apps import OverlayBaseApp + from sksurgeryutils.common_overlay_apps import OverlayBaseWidget -scikit-surgery provides an `OverlayBaseApp`_ module that creates a qtwidget showing +scikit-surgery provides an `OverlayBaseWidget`_ module that creates a qtwidget showing a live stream from a video source, overlaid with a rendered surface model. scikit-surgery leaves the update method unimplemented so that the user can implement their own version in an child class. :: - #create an OverlayApp class, that inherits from OverlayBaseApp - class OverlayApp(OverlayBaseApp): + #create an OverlayApp class, that inherits from OverlayBaseWidget + class OverlayApp(OverlayBaseWidget): and implement a minimal update method :: - def update(self): + def update_view(self): #read a new image from the video source _, image = self.video_source.read() @@ -57,27 +57,30 @@ video above from the `project repository`_, or use a model of your own. :: - #first we create an application - app = QApplication([]) + if __name__ == '__main__': + #first we create an application + app = QApplication([]) - #then an instance of OverlayApp. The video source - #is set when we create the instance. This is an index - #starting at 0. If you have more than one webcam, you can - #try using different numbered sources - video_source = 0 - viewer = OverlayApp(video_source) + #then an instance of OverlayApp. The video source + #is set when we create the instance. This is an index + #starting at 0. If you have more than one webcam, you can + #try using different numbered sources + video_source = 0 + viewer = OverlayApp(video_source) - #Set a model directory containing the models you wish - #to render and optionally a colours.txt defining the - #colours to render in. - model_dir = '../models' - viewer.add_vtk_models_from_dir(model_dir) + #Set a model directory containing the models you wish + #to render and optionally a colours.txt defining the + #colours to render in. + model_dir = '../models' + viewer.add_vtk_models_from_dir(model_dir) - #start the viewer - viewer.start() + #start the viewer + viewer.show() + viewer.start() + + #start the application + sys.exit(app.exec_()) - #start the application - sys.exit(app.exec_()) Now run the application with @@ -98,6 +101,8 @@ for each frame update. .. _`PySide2`: https://pypi.org/project/PySide2 .. _`OpenCV` : https://pypi.org/project/opencv-contrib-python .. _`VTK` : https://pypi.org/project/vtk -.. _`OverlayBaseApp` : https://scikit-surgeryutils.readthedocs.io/en/latest/sksurgeryutils.common_overlay_apps.html#module-sksurgeryutils.common_overlay_apps.OverlayBaseApp +.. _`OverlayBaseWidget` : https://scikit-surgeryutils.readthedocs.io/en/latest/sksurgeryutils.common_overlay_apps.html#module-sksurgeryutils.common_overlay_apps.OverlayBaseWidget .. _`finished example` : https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01/blob/master/sksurgerytutorial01/vtkoverlay_app.py .. _`project repository` : https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01/blob/master/models +.. _ pycharm` : https://www.jetbrains.com/pycharm/download/#section=linux +.. _ vscode` : https://code.visualstudio.com/ diff --git a/doc/02_VTK_Overlay_With_Movement.rst b/doc/02_VTK_Overlay_With_Movement.rst index 00c1aed..fd40329 100644 --- a/doc/02_VTK_Overlay_With_Movement.rst +++ b/doc/02_VTK_Overlay_With_Movement.rst @@ -25,9 +25,9 @@ method called _move_model. .. code-block:: python :emphasize-lines: 4,5 - def update(self): + def update_view(self): _, image = self.video_source.read() - + #add a method to move the rendered models self._move_model() @@ -59,6 +59,7 @@ Leave the rest of the file as is, and try running the application with or similar. If successful you should see a live video stream overlaid with a rendered surface model. The surface model should slowly rotate, like in the video at the top of the page. Congratulations. + Note that you can still use the VTK interactor to move the camera around or change the model representation. Have a play around and see how it interacts with the model rotation. diff --git a/doc/03_VTK_Overlay_With_Aruco_Tag.rst b/doc/03_VTK_Overlay_With_Aruco_Tag.rst index f4aa04f..cb13315 100644 --- a/doc/03_VTK_Overlay_With_Aruco_Tag.rst +++ b/doc/03_VTK_Overlay_With_Aruco_Tag.rst @@ -21,7 +21,7 @@ it in front of the camera. Something like ... 02 - Add a feature detector and follower ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -**You'll need an ArUco tag to track, print out** +**You'll need an ArUco tag to track, print it out in A4** `this one`_ . Create a copy of vtkoverlay_with_movement_app.py and call it @@ -46,7 +46,7 @@ We'll also need NumPy to handle arrays; import numpy -Set up SciKit-SurgeryArUcoTracker in the __init__ function. +Set up SciKit-SurgeryArUcoTracker in the __init__ function of OverlayApp Class. :: @@ -64,7 +64,7 @@ Set up SciKit-SurgeryArUcoTracker in the __init__ function. "debug": False, #the aruco tag dictionary to use. DICT_4X4_50 will work with #../tags/aruco_4by4_0.pdf - "dictionary" : 'DICT_4X4_50', + "aruco dictionary" : 'DICT_4X4_50', "marker size": 50, # in mm #We need a calibrated camera. For now let's just use a #a hard coded estimate. Maybe you could improve on this. @@ -91,7 +91,7 @@ self._move_model() with self._aruco_detect_and_follow(). .. code-block:: python :emphasize-lines: 4,5 - def update(self): + def update_view(self): _, image = self.video_source.read() #add a method to move the rendered models @@ -175,11 +175,11 @@ You can download a You can also download the completed tutorial, either using git; :: - git clone https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01 + git clone https://github.com/SciKit-Surgery/scikit-surgerytutorial01 or by downloading the files directly from -https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01 +https://github.com/SciKit-Surgery/scikit-surgerytutorial01 That completes this tutorial. Please get in touch with any feedback or issues. You can use the issue tracker at the `Project homepage`_. @@ -194,4 +194,4 @@ use the issue tracker at the `Project homepage`_. .. _`finished example` : https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01/blob/master/sksurgerytutorial01/vtk_aruco_app.py .. _`OpenCV ArUco tutorial` : https://docs.opencv.org/3.4/d5/dae/tutorial_aruco_detection.html .. _`Project homepage` : https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01 -.. _`this one`: https://github.com/SciKit-Surgery/SciKit-SurgeryTutorial01/blob/master/tags/tag_sheet_sksurgery01.pdf +.. _`this one`: https://github.com/SciKit-Surgery/scikit-surgerytutorial01/blob/master/tags/tag_sheet_snappy01.pdf diff --git a/requirements.txt b/requirements.txt index 85feb7c..4fc3e80 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,6 @@ # doc/requirements.rst numpy>=1.17.4 PySide2 -scikit-surgerycore -scikit-surgeryutils>=0.6.2 -scikit-surgeryarucotracker>=0.1.1 +scikit-surgerycore>=0.1.7 +scikit-surgeryutils>=1.2.0 +scikit-surgeryarucotracker>= 0.2.7 \ No newline at end of file diff --git a/sksurgerytutorial01/vtk_aruco_app.py b/sksurgerytutorial01/vtk_aruco_app.py index 88cf1fd..ddd3cbe 100644 --- a/sksurgerytutorial01/vtk_aruco_app.py +++ b/sksurgerytutorial01/vtk_aruco_app.py @@ -7,12 +7,12 @@ #add an import for numpy, to manipulate arrays import numpy from PySide2.QtWidgets import QApplication -from sksurgeryutils.common_overlay_apps import OverlayBaseApp +from sksurgeryutils.common_overlay_apps import OverlayBaseWidget from sksurgerycore.transforms.transform_manager import TransformManager from sksurgeryarucotracker.arucotracker import ArUcoTracker -class OverlayApp(OverlayBaseApp): - """Inherits from OverlayBaseApp, and adds methods to +class OverlayApp(OverlayBaseWidget): + """Inherits from OverlayBaseWidget, and adds methods to detect aruco tags and move the model to follow.""" def __init__(self, image_source): @@ -24,7 +24,7 @@ def __init__(self, image_source): ar_config = { "tracker type": "aruco", - #Set to none, to share video source with OverlayBaseApp + #Set to none, to share video source with OverlayBaseWidget "video source": 'none', "debug": False, #the aruco tag dictionary to use. DICT_4X4_50 will work with @@ -47,9 +47,9 @@ def __init__(self, image_source): super().__init__(image_source) else: #super doesn't work the same in py2.7 - OverlayBaseApp.__init__(self, image_source) + OverlayBaseWidget.__init__(self, image_source) - def update(self): + def update_view(self): """Update the background render with a new frame and scan for aruco tags""" _, image = self.video_source.read() @@ -101,6 +101,7 @@ def _move_camera(self, tag2camera): model_dir = '../models' viewer.add_vtk_models_from_dir(model_dir) + viewer.show() viewer.start() sys.exit(app.exec_()) diff --git a/sksurgerytutorial01/vtkoverlay_app.py b/sksurgerytutorial01/vtkoverlay_app.py index d189686..7deb70f 100644 --- a/sksurgerytutorial01/vtkoverlay_app.py +++ b/sksurgerytutorial01/vtkoverlay_app.py @@ -5,13 +5,13 @@ import sys from PySide2.QtWidgets import QApplication -from sksurgeryutils.common_overlay_apps import OverlayBaseApp +from sksurgeryutils.common_overlay_apps import OverlayBaseWidget #create an OverlayApp class, that inherits from OverlayBaseApp -class OverlayApp(OverlayBaseApp): +class OverlayApp(OverlayBaseWidget): """Inherits from OverlayBaseApp, and adds a minimal implementation of update. """ - def update(self): + def update_view(self): """Update the background renderer with a new frame, and render""" _, image = self.video_source.read() @@ -39,6 +39,7 @@ def update(self): viewer.add_vtk_models_from_dir(model_dir) #start the viewer + viewer.show() viewer.start() #start the application diff --git a/sksurgerytutorial01/vtkoverlay_with_movement_app.py b/sksurgerytutorial01/vtkoverlay_with_movement_app.py index 11682b1..1e611fa 100644 --- a/sksurgerytutorial01/vtkoverlay_with_movement_app.py +++ b/sksurgerytutorial01/vtkoverlay_with_movement_app.py @@ -5,13 +5,13 @@ import sys from PySide2.QtWidgets import QApplication -from sksurgeryutils.common_overlay_apps import OverlayBaseApp +from sksurgeryutils.common_overlay_apps import OverlayBaseWidget -class OverlayApp(OverlayBaseApp): - """Inherits from OverlayBaseApp, and adds a minimal - implementation of update. """ +class OverlayApp(OverlayBaseWidget): + """Inherits from OverlayBaseWidget, and adds a minimal + implementation of update_view. """ - def update(self): + def update_view(self): """Update the background renderer with a new frame, move the model and render""" _, image = self.video_source.read() @@ -45,6 +45,7 @@ def _move_model(self): model_dir = '../models' viewer.add_vtk_models_from_dir(model_dir) + viewer.show() viewer.start() sys.exit(app.exec_()) diff --git a/tests/test_sksurgerytorial01.py b/tests/test_sksurgerytorial01.py index cd0d0bb..0c841b5 100644 --- a/tests/test_sksurgerytorial01.py +++ b/tests/test_sksurgerytorial01.py @@ -1,5 +1,5 @@ # coding=utf-8 - + """sksurgerytutorial01 vtkoverlay tests""" import pytest @@ -8,25 +8,29 @@ from sksurgerytutorial01.vtkoverlay_app import OverlayApp as vtkoverlay from sksurgerytutorial01.vtkoverlay_with_movement_app import OverlayApp as vtkmovingoverlay + def test_vtk_aruco_app(setup_qt): pass - viewer = aruco(image_source = 'data/output.avi') + viewer = aruco(image_source='data/output.avi') viewer.add_vtk_models_from_dir('models') + viewer.show() viewer.start() viewer.stop() + def test_vtkoverlay_app(setup_qt): pass - viewer = vtkoverlay(video_source = 'data/output.avi') + viewer = vtkoverlay(video_source='data/output.avi') viewer.add_vtk_models_from_dir('models') + viewer.show() viewer.start() viewer.stop() + def test_vtkoverlay_with_movement_app(setup_qt): pass - viewer = vtkmovingoverlay(video_source = 'data/output.avi') + viewer = vtkmovingoverlay(video_source='data/output.avi') viewer.add_vtk_models_from_dir('models') + viewer.show() viewer.start() viewer.stop() - -