Commit 7f7a9309 authored by Matt Clarkson's avatar Matt Clarkson

Merge branch '3-update-pyside'

parents 664a2ae8 9d2e705e
Pipeline #792 passed with stages
in 17 minutes and 10 seconds
......@@ -60,10 +60,15 @@ build windows installer:
test Linux:
stage: test
variables:
LD_LIBRARY_PATH: ${CI_PROJECT_DIR}/.tox/py36/lib/python3.6/site-packages/PySide2/Qt/plugins/platforms
DISPLAY: localhost:0
script:
- echo "LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
- echo "DISPLAY=${DISPLAY}"
- tox
tags:
- shared-linux
- shared-linux, gui
coverage: '/^TOTAL.*\s+(\d+\%)$/'
......@@ -72,7 +77,7 @@ test macOS:
script:
- tox
tags:
- shared-mac
- shared-mac, gui
test Windows:
......@@ -80,7 +85,7 @@ test Windows:
script:
- tox
tags:
- shared-win
- shared-win, gui
deploy docs to staging:
......
......@@ -18,11 +18,12 @@ scikit-surgeryvideoutils
:target: http://scikit-surgeryvideoutils.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
scikit-surgeryvideoutils is a python project containing a few test and demo
utilities, based around opencv-contrib-python for video processing and
PySide2 for GUI windows and widgets.
scikit-surgeryvideoutils is a python project that does interesting things.
Author: Matt Clarkson
* sksurgeryvideolag.py - shows a millisecond timer and video image to measure lag
* sksurgerycharucotest.py - extracts charuco points and annotates video image with each id detected.
scikit-surgeryvideoutils is part of the `SNAPPY`_ software project, developed at the `Wellcome EPSRC Centre for Interventional and Surgical Sciences`_, part of `University College London (UCL)`_.
......
/sksurgeryvideoutils.rst
/sksurgeryvideoutils.*.rst
/sksurgeryvideolag.rst
/sksurgerycharucotest.rst
/modules.rst
/versioneer.rst
/build
......@@ -2,9 +2,8 @@
# It is used by pip to manage software dependencies. It is not to be
# confused with the software requirements, which are listed in
# doc/requirements.rst
numpy
six
opencv-contrib-python
--extra-index-url http://download.qt.io/snapshots/ci/pyside/5.9/latest/ --trusted-host download.qt.io
PySide2
scikit-surgeryimage
six>=1.10
numpy>=1.11
opencv-contrib-python>=3.4.4
PySide2>=5.12.0
scikit-surgeryimage>=0.1.1
......@@ -55,7 +55,7 @@ setup(
'numpy>=1.11',
'opencv-contrib-python>=3.4.4',
'PySide2>=5.12.0',
'scikit-surgeryimage>=0.1.0',
'scikit-surgeryimage>=0.1.1',
],
entry_points={
......
......@@ -18,23 +18,35 @@ def main(args=None):
type=int,
help="Camera index.")
parser.add_argument("-x", "--x_squares",
parser.add_argument("-x", "--x_size",
required=False,
default=13,
default=640,
type=int,
help="Number of squares in X direction.")
help="Image width")
parser.add_argument("-y", "--y_squares",
parser.add_argument("-y", "--y_size",
required=False,
default=480,
type=int,
help="Image height")
parser.add_argument("-i", "--horizontal",
required=False,
default=10,
type=int,
help="Number of squares in Y direction.")
help="Number of squares horizontally.")
parser.add_argument("-j", "--vertical",
required=False,
default=13,
type=int,
help="Number of squares vertically.")
parser.add_argument("-d", "--dictionary",
required=True,
required=False,
default=2,
type=int,
help="ArUco dictionary enum.")
help="ArUco dictionary enum. (see online)")
version_string = __version__
friendly_version_string = version_string if version_string else 'unknown'
......@@ -46,7 +58,9 @@ def main(args=None):
args = parser.parse_args(args)
run_demo(args.camera,
args.x_squares,
args.y_squares,
args.x_size,
args.y_size,
args.horizontal,
args.vertical,
args.dictionary
)
......@@ -15,7 +15,7 @@ import sksurgeryvideoutils.utils.image_utils as iu
class CharucoDemoGui(QtWidgets.QWidget):
""" Demo GUI, with 2 QLabel side by side."""
def __init__(self, camera, x_squares, y_squares, dictionary):
def __init__(self, camera, width, height, rows, columns, dictionary):
super().__init__()
if camera < 0:
......@@ -28,6 +28,8 @@ class CharucoDemoGui(QtWidgets.QWidget):
raise ValueError('dictionary should be an ArUco enum of dictionary')
self.cap = cv2.VideoCapture(camera) # pylint: disable=no-member
self.cap.set(3, width)
self.cap.set(4, height)
if not self.cap.isOpened():
raise ValueError("Unable to open camera:" + str(camera))
......@@ -36,10 +38,18 @@ class CharucoDemoGui(QtWidgets.QWidget):
if not grabbed:
raise RuntimeError("Failed to grab first frame.")
if self.frame.shape[0] != height:
raise ValueError("Grabbed image has wrong number of rows:"
+ str(self.frame.shape[0]))
if self.frame.shape[1] != width:
raise ValueError("Grabbed image has wrong number of columns:"
+ str(self.frame.shape[1]))
# pylint: disable=no-member
self.dictionary = aruco.Dictionary_get(dictionary)
self.board = aruco.CharucoBoard_create(x_squares,
y_squares,
self.board = aruco.CharucoBoard_create(rows,
columns,
2,
1,
self.dictionary)
......@@ -103,17 +113,20 @@ class CharucoDemoGui(QtWidgets.QWidget):
self.image_label.setPixmap(pixmap)
def run_demo(camera, width, height, dictionary):
def run_demo(camera, width, height, rows, columns, dictionary):
""" Prints command line args, and launches main screen."""
six.print_("Camera:" + str(camera))
six.print_(" Width:" + str(width))
six.print_(" Height:" + str(height))
six.print_("Dictionary:" + str(dictionary))
six.print_("Board:")
six.print_(" Rows:" + str(rows))
six.print_(" Columns:" + str(columns))
six.print_(" Dictionary:" + str(dictionary))
app = QtWidgets.QApplication([])
widget = CharucoDemoGui(camera, width, height, dictionary)
widget = CharucoDemoGui(camera, width, height, rows, columns, dictionary)
widget.show()
return sys.exit(app.exec_())
......@@ -4,37 +4,32 @@
Various image utilities that might be useful in this package.
"""
import sys
import ctypes
import numpy as np
from PySide2 import QtGui
def image_to_pixmap(image):
def image_to_pixmap(rgb_image):
"""
Converts an OpenCV image to a Qt pixmap.
:param image: OpenCV image, 3 channel, RGB.
:param rgb_image: OpenCV image, 3 channel, RGB.
:return: QPixmap
"""
if not isinstance(image, np.ndarray):
if not isinstance(rgb_image, np.ndarray):
raise TypeError('Input should be a numpy nd.array')
if image.shape[2] != 3:
if rgb_image.shape[2] != 3:
raise ValueError('Input should be 3 channel RGB')
# Workaround for memory leak.
# If you see a memory leak.
# See: https://bugreports.qt.io/browse/PYSIDE-140
# Should be fixed properly in PySide 5.11.3
# Once we upgrade to 5.11.3, take out the hack on
# the ch and rcount variables, and just create qimage
# and then instantiate pixmap from qimage.
pointer_to_buffer = ctypes.c_char.from_buffer(image, 0)
rcount = ctypes.c_long.from_address(id(pointer_to_buffer)).value
qimage = QtGui.QImage(pointer_to_buffer,
image.shape[1],
image.shape[0],
QtGui.QImage.Format_RGB888)
if sys.version[0] == '3':
ctypes.c_long.from_address(id(pointer_to_buffer)).value = rcount
pixmap = QtGui.QPixmap.fromImage(qimage)
return pixmap
# Should be fixed properly in PySide 5.11.3.
# As of this commit, we should be on 5.12.0.
# You could double check your environment.
q_image = QtGui.QImage(rgb_image.data,
rgb_image.shape[1],
rgb_image.shape[0],
rgb_image.shape[1] * 3,
QtGui.QImage.Format_RGB888)
pix = QtGui.QPixmap(q_image)
return pix
# -*- coding: utf-8 -*-
import pytest
from PySide2.QtWidgets import QApplication
@pytest.fixture(scope="module")
def setup_qt():
""" Create the QT application. """
app = QApplication([])
return app
# coding=utf-8
import pytest
import numpy as np
import sksurgeryvideoutils.utils.image_utils as iu
def test_image_to_pixmap_greyscale():
pass
def test_image_to_pixel_invalid_because_input_is_none():
with pytest.raises(TypeError):
iu.image_to_pixmap(None)
def test_image_to_pixmap_rgb():
pass
def test_image_to_pixel_invalid_because_input_is_not_numpy():
with pytest.raises(TypeError):
iu.image_to_pixmap(1)
def test_image_to_pixel_invalid_because_input_is_greyscale():
with pytest.raises(ValueError):
iu.image_to_pixmap(np.zeros((100, 50, 1), dtype=np.uint8))
def test_image_to_pixel_valid_rgb_example(setup_qt):
app = setup_qt
blank_image = np.zeros((50, 100, 3), dtype=np.uint8)
pixmap = iu.image_to_pixmap(blank_image)
assert pixmap.width() == blank_image.shape[1]
assert pixmap.height() == blank_image.shape[0]
# content of: tox.ini , put in same dir as setup.py
[tox]
envlist = py27,py36,lint
envlist = py36,lint
skipsdist = True
[travis]
python =
2.7: py27
3.6: py36, docs, lint
[testenv]
passenv = *
deps=-rrequirements-dev.txt
whitelist_externals=coverage,pip
# See .coveragerc for list of omitted files
......@@ -31,12 +31,6 @@ commands = sphinx-build -M html . build
basepython=python3.6
commands=python -c "print('Installer not needed for this project.')"
[testenv:pip2]
basepython=python2.7
changedir=pip_test
skip_install=True
commands = pip install {posargs}
[testenv:pip3]
basepython=python3.6
changedir=pip_test
......
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