useCupy option should be settable after ImageItem init (#1749)

* do not cache the cupy so the config option can be set later

* getCupy will always return None if the option is not set

* test of failing behavior

* divorce skip from option; restore option after test
This commit is contained in:
Martin Chase 2021-04-30 10:41:11 -07:00 committed by GitHub
parent 7dc4823cc6
commit 85e2574230
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 32 deletions

View File

@ -60,7 +60,6 @@ class ImageItem(GraphicsObject):
self._displayBuffer = None
self._renderRequired = True
self._unrenderable = False
self._cupy = getCupy()
self._xp = None # either numpy or cupy, to match the image data
self._defferedLevels = None
@ -216,7 +215,7 @@ class ImageItem(GraphicsObject):
def _buildQImageBuffer(self, shape):
self._displayBuffer = numpy.empty(shape[:2] + (4,), dtype=numpy.ubyte)
if self._xp == self._cupy:
if self._xp == getCupy():
self._processingBuffer = self._xp.empty(shape[:2] + (4,), dtype=self._xp.ubyte)
else:
self._processingBuffer = self._displayBuffer
@ -273,7 +272,8 @@ class ImageItem(GraphicsObject):
return
else:
old_xp = self._xp
self._xp = self._cupy.get_array_module(image) if self._cupy else numpy
cp = getCupy()
self._xp = cp.get_array_module(image) if cp else numpy
gotNewData = True
processingSubstrateChanged = old_xp != self._xp
if processingSubstrateChanged:
@ -449,7 +449,7 @@ class ImageItem(GraphicsObject):
self._buildQImageBuffer(image.shape)
fn.makeARGB(image, lut=lut, levels=levels, output=self._processingBuffer)
if self._xp == self._cupy:
if self._xp == getCupy():
self._processingBuffer.get(out=self._displayBuffer)
self._renderRequired = False
self._unrenderable = False
@ -535,22 +535,23 @@ class ImageItem(GraphicsObject):
kwds['bins'] = bins
cp = getCupy()
if perChannel:
hist = []
for i in range(stepData.shape[-1]):
stepChan = stepData[..., i]
stepChan = stepChan[self._xp.isfinite(stepChan)]
h = self._xp.histogram(stepChan, **kwds)
if self._cupy:
hist.append((self._cupy.asnumpy(h[1][:-1]), self._cupy.asnumpy(h[0])))
if cp:
hist.append((cp.asnumpy(h[1][:-1]), cp.asnumpy(h[0])))
else:
hist.append((h[1][:-1], h[0]))
return hist
else:
stepData = stepData[self._xp.isfinite(stepData)]
hist = self._xp.histogram(stepData, **kwds)
if self._cupy:
return self._cupy.asnumpy(hist[1][:-1]), self._cupy.asnumpy(hist[0])
if cp:
return cp.asnumpy(hist[1][:-1]), cp.asnumpy(hist[0])
else:
return hist[1][:-1], hist[0]

View File

@ -1,15 +1,39 @@
# -*- coding: utf-8 -*-
import time
import pytest
from pyqtgraph.Qt import QtCore, QtGui, QtTest
import numpy as np
import pyqtgraph as pg
from pyqtgraph.tests 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)
def test_ImageItem(transpose=False):
w = pg.GraphicsLayoutWidget()
w.show()
view = pg.ViewBox()
@ -123,6 +147,7 @@ def test_ImageItem(transpose=False):
w.hide()
def test_ImageItem_axisorder():
# All image tests pass again using the opposite axis order
origMode = pg.getConfigOption('imageAxisOrder')

View File

@ -6,6 +6,10 @@ from typing import Dict, Any, Union, Type
from pyqtgraph import getCupy, getConfigOption, setConfigOption
from pyqtgraph.functions import makeARGB as real_makeARGB
try:
import cupy
except ImportError:
cupy = None
IN_2D_INT8 = np.array([[173, 48, 122, 41], [210, 192, 0, 5], [104, 56, 102, 115], [78, 19, 255, 6]], dtype=np.uint8)
IN_RGB_INT8 = np.array(
@ -4290,30 +4294,36 @@ def test_makeARGB_against_generated_references():
_do_something_for_every_combo(assert_correct)
@pytest.mark.skipif(getCupy() is None, reason="CuPy unavailable to test")
@pytest.mark.skipif(cupy is None, reason="CuPy unavailable to test")
def test_cupy_makeARGB_against_generated_references():
setConfigOption("useCupy", True)
cp = getCupy()
def assert_cupy_correct(data, key, levels, lut, scale, use_rgba):
data = cp.asarray(data)
if lut is not None:
lut = cp.asarray(lut)
expectation = EXPECTED_OUTPUTS[key]
if isinstance(expectation, type) and issubclass(expectation, Exception):
try:
_makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba)
except Exception as e:
assert expectation == type(e)
else:
assert False, f"makeARGB({key!r}) was supposed to raise {expectation} but didn't raise anything."
else:
expectation = cp.asarray(expectation)
output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba)
assert (
output == expectation
).all(), f"Incorrect _makeARGB({key!r}) output! Expected:\n{expectation!r}\n Got:\n{output!r}"
prev_setting = getConfigOption("useCupy")
try:
setConfigOption("useCupy", True)
_do_something_for_every_combo(assert_cupy_correct)
cupy = getCupy()
def assert_cupy_correct(data, key, levels, lut, scale, use_rgba):
data = cupy.asarray(data)
if lut is not None:
lut = cupy.asarray(lut)
expectation = EXPECTED_OUTPUTS[key]
if isinstance(expectation, type) and issubclass(expectation, Exception):
try:
_makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba)
except Exception as e:
assert expectation == type(e)
else:
assert False, f"makeARGB({key!r}) was supposed to raise {expectation} but didn't raise anything."
else:
expectation = cupy.asarray(expectation)
output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba)
assert (
output == expectation
).all(), f"Incorrect _makeARGB({key!r}) output! Expected:\n{expectation!r}\n Got:\n{output!r}"
_do_something_for_every_combo(assert_cupy_correct)
finally:
setConfigOption("useCupy", prev_setting)
@pytest.mark.filterwarnings("ignore:invalid value encountered")

View File

@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
import os
from warnings import warn
from .. import getConfigOption
def getCupy():
if getConfigOption("useCupy"):
try: