e7a30b9324
Remove if __name__ == "__main__" bits, replace some == None to is None checks Cleanup variety of static code checker issue Removed missing imports, restructured some logic to make a little cleaner, fixed a function in test_dockarea, unfortunately broke the test so now I tell pytest to expect the Exception.
199 lines
7.3 KiB
Python
199 lines
7.3 KiB
Python
# -*- coding: utf-8 -*-
|
|
import time
|
|
import pytest
|
|
|
|
from pyqtgraph.Qt import QtGui, QtTest
|
|
import numpy as np
|
|
import pyqtgraph as pg
|
|
from tests.image_testing import assertImageApproved, TransposedImageItem
|
|
try:
|
|
import cupy
|
|
except ImportError:
|
|
cupy = None
|
|
app = pg.mkQApp()
|
|
|
|
|
|
@pytest.mark.skipif(cupy is None, reason="CuPy unavailable to test")
|
|
def test_useCupy_can_be_set_after_init():
|
|
prev_setting = pg.getConfigOption("useCupy")
|
|
try:
|
|
pg.setConfigOption("useCupy", False)
|
|
w = pg.GraphicsLayoutWidget()
|
|
w.show()
|
|
view = pg.ViewBox()
|
|
w.setCentralWidget(view)
|
|
w.resize(200, 200)
|
|
img = cupy.random.randint(0, 255, size=(32, 32)).astype(cupy.uint8)
|
|
ii = pg.ImageItem()
|
|
view.addItem(ii)
|
|
pg.setConfigOption("useCupy", True)
|
|
ii.setImage(img)
|
|
w.hide()
|
|
finally:
|
|
pg.setConfigOption("useCupy", prev_setting)
|
|
|
|
|
|
@pytest.mark.skipif(cupy is None, reason="CuPy unavailable to test")
|
|
def test_ensuring_substrate():
|
|
prev_setting = pg.getConfigOption("useCupy")
|
|
try:
|
|
pg.setConfigOption("useCupy", True)
|
|
ii = pg.ImageItem()
|
|
|
|
data = cupy.random.randint(0, 255, size=(32, 32)).astype(cupy.uint8)
|
|
assert data is ii._ensure_proper_substrate(data, cupy)
|
|
assert isinstance(ii._ensure_proper_substrate(data, cupy), cupy.ndarray)
|
|
assert data is not ii._ensure_proper_substrate(data, np)
|
|
assert isinstance(ii._ensure_proper_substrate(data, np), np.ndarray)
|
|
|
|
data = np.random.randint(0, 255, size=(32, 32)).astype(np.uint8)
|
|
assert data is ii._ensure_proper_substrate(data, np)
|
|
assert isinstance(ii._ensure_proper_substrate(data, np), np.ndarray)
|
|
assert data is not ii._ensure_proper_substrate(data, cupy)
|
|
assert isinstance(ii._ensure_proper_substrate(data, cupy), cupy.ndarray)
|
|
|
|
data = range(0, 255)
|
|
assert data is not ii._ensure_proper_substrate(data, np)
|
|
assert isinstance(ii._ensure_proper_substrate(data, np), np.ndarray)
|
|
assert data is not ii._ensure_proper_substrate(data, cupy)
|
|
assert isinstance(ii._ensure_proper_substrate(data, cupy), cupy.ndarray)
|
|
finally:
|
|
pg.setConfigOption("useCupy", prev_setting)
|
|
|
|
|
|
def test_ImageItem(transpose=False):
|
|
w = pg.GraphicsLayoutWidget()
|
|
w.show()
|
|
view = pg.ViewBox()
|
|
w.setCentralWidget(view)
|
|
w.resize(200, 200)
|
|
img = TransposedImageItem(border=0.5, transpose=transpose)
|
|
|
|
view.addItem(img)
|
|
|
|
# test mono float
|
|
np.random.seed(0)
|
|
data = np.random.normal(size=(20, 20))
|
|
dmax = data.max()
|
|
data[:10, 1] = dmax + 10
|
|
data[1, :10] = dmax + 12
|
|
data[3, :10] = dmax + 13
|
|
img.setImage(data)
|
|
|
|
QtTest.QTest.qWaitForWindowExposed(w)
|
|
time.sleep(0.1)
|
|
app.processEvents()
|
|
assertImageApproved(w, 'imageitem/init', 'Init image item. View is auto-scaled, image axis 0 marked by 1 line, axis 1 is marked by 2 lines. Origin in bottom-left.')
|
|
|
|
# ..with colormap
|
|
cmap = pg.ColorMap([0, 0.25, 0.75, 1], [[0, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255]])
|
|
img.setLookupTable(cmap.getLookupTable())
|
|
assertImageApproved(w, 'imageitem/lut', 'Set image LUT.')
|
|
|
|
# ..and different levels
|
|
img.setLevels([dmax+9, dmax+13])
|
|
assertImageApproved(w, 'imageitem/levels1', 'Levels show only axis lines.')
|
|
|
|
img.setLookupTable(None)
|
|
|
|
# test mono int
|
|
data = np.fromfunction(lambda x,y: x+y*10, (129, 128)).astype(np.int16)
|
|
img.setImage(data)
|
|
assertImageApproved(w, 'imageitem/gradient_mono_int', 'Mono int gradient.')
|
|
|
|
img.setLevels([640, 641])
|
|
assertImageApproved(w, 'imageitem/gradient_mono_int_levels', 'Mono int gradient w/ levels to isolate diagonal.')
|
|
|
|
# test mono byte
|
|
data = np.fromfunction(lambda x,y: x+y, (129, 128)).astype(np.ubyte)
|
|
img.setImage(data)
|
|
assertImageApproved(w, 'imageitem/gradient_mono_byte', 'Mono byte gradient.')
|
|
|
|
img.setLevels([127, 128])
|
|
assertImageApproved(w, 'imageitem/gradient_mono_byte_levels', 'Mono byte gradient w/ levels to isolate diagonal.')
|
|
|
|
# test monochrome image
|
|
data = np.zeros((10, 10), dtype='uint8')
|
|
data[:5,:5] = 1
|
|
data[5:,5:] = 1
|
|
img.setImage(data)
|
|
assertImageApproved(w, 'imageitem/monochrome', 'Ubyte image with only 0,1 values.')
|
|
|
|
# test bool
|
|
data = data.astype(bool)
|
|
img.setImage(data)
|
|
assertImageApproved(w, 'imageitem/bool', 'Boolean mask.')
|
|
|
|
# test RGBA byte
|
|
data = np.zeros((100, 100, 4), dtype='ubyte')
|
|
data[..., 0] = np.linspace(0, 255, 100).reshape(100, 1)
|
|
data[..., 1] = np.linspace(0, 255, 100).reshape(1, 100)
|
|
data[..., 3] = 255
|
|
img.setImage(data)
|
|
assertImageApproved(w, 'imageitem/gradient_rgba_byte', 'RGBA byte gradient.')
|
|
|
|
img.setLevels([[128, 129], [128, 255], [0, 1], [0, 255]])
|
|
assertImageApproved(w, 'imageitem/gradient_rgba_byte_levels', 'RGBA byte gradient. Levels set to show x=128 and y>128.')
|
|
|
|
# test RGBA float
|
|
data = data.astype(float)
|
|
img.setImage(data / 1e9)
|
|
assertImageApproved(w, 'imageitem/gradient_rgba_float', 'RGBA float gradient.')
|
|
|
|
# checkerboard to test alpha
|
|
img2 = TransposedImageItem(transpose=transpose)
|
|
img2.setImage(np.fromfunction(lambda x,y: (x+y)%2, (10, 10)), levels=[-1,2])
|
|
view.addItem(img2)
|
|
img2.setScale(10)
|
|
img2.setZValue(-10)
|
|
|
|
data[..., 0] *= 1e-9
|
|
data[..., 1] *= 1e9
|
|
data[..., 3] = np.fromfunction(lambda x,y: np.sin(0.1 * (x+y)), (100, 100))
|
|
img.setImage(data, levels=[[0, 128e-9],[0, 128e9],[0, 1],[-1, 1]])
|
|
assertImageApproved(w, 'imageitem/gradient_rgba_float_alpha', 'RGBA float gradient with alpha.')
|
|
|
|
# test composition mode
|
|
img.setCompositionMode(QtGui.QPainter.CompositionMode_Plus)
|
|
assertImageApproved(w, 'imageitem/gradient_rgba_float_additive', 'RGBA float gradient with alpha and additive composition mode.')
|
|
|
|
img2.hide()
|
|
img.setCompositionMode(QtGui.QPainter.CompositionMode_SourceOver)
|
|
|
|
# test downsampling
|
|
data = np.fromfunction(lambda x,y: np.cos(0.002 * x**2), (800, 100))
|
|
img.setImage(data, levels=[-1, 1])
|
|
assertImageApproved(w, 'imageitem/resolution_without_downsampling', 'Resolution test without downsampling.')
|
|
|
|
img.setAutoDownsample(True)
|
|
assertImageApproved(w, 'imageitem/resolution_with_downsampling_x', 'Resolution test with downsampling axross x axis.')
|
|
assert img._lastDownsample == (4, 1)
|
|
|
|
img.setImage(data.T, levels=[-1, 1])
|
|
assertImageApproved(w, 'imageitem/resolution_with_downsampling_y', 'Resolution test with downsampling across y axis.')
|
|
assert img._lastDownsample == (1, 4)
|
|
|
|
w.hide()
|
|
|
|
|
|
def test_ImageItem_axisorder():
|
|
# All image tests pass again using the opposite axis order
|
|
origMode = pg.getConfigOption('imageAxisOrder')
|
|
altMode = 'row-major' if origMode == 'col-major' else 'col-major'
|
|
pg.setConfigOptions(imageAxisOrder=altMode)
|
|
try:
|
|
test_ImageItem(transpose=True)
|
|
finally:
|
|
pg.setConfigOptions(imageAxisOrder=origMode)
|
|
|
|
|
|
def test_dividebyzero():
|
|
im = pg.image(pg.np.random.normal(size=(100,100)))
|
|
im.imageItem.setAutoDownsample(True)
|
|
im.view.setRange(xRange=[-5+25, 5e+25],yRange=[-5e+25, 5e+25])
|
|
app.processEvents()
|
|
QtTest.QTest.qWait(1000)
|
|
# must manually call im.imageItem.render here or the exception
|
|
# will only exist on the Qt event loop
|
|
im.imageItem.render()
|