pyqtgraph/tests/graphicsItems/test_ImageItemFormat.py

169 lines
7.7 KiB
Python
Raw Normal View History

Bypass makeARGB in some cases (#1786) * refactor out _ndarray_to_qimage() * combine levels back with lut * make use of Grayscale8, RGB888 and Indexed8 QImage formats Grayscale8 and RGB888 images are those that are ready for display without further processing. * add Grayscale16 * apply the efflut early for uint16 mono/rgb, uint8 rgb * ndarray indexing is faster than np.take * handle uint16 rgb(a) with no levels same as levels=[0, 65535] * add support for Format_RGBA64 * fix: support colormaps of shape (h, 1) * check ImageItem uint8 and uint16 QImage formats * uint16 mono with rgb lut -> RGBX8888 * got width and height swapped in array dimensions * set ImageItem as row-major * no need to form a 1d 32-bit lut for array indexing you can index (y, x) into a lookup table of shape (nentry, 3) or (nentry, 4) and get an output of shape (y, x, 3) or (y, x, 4) * Revert "no need to form a 1d 32-bit lut for array indexing" This reverts commit 45cf3100de637ed7e53ebb565fbb840ae1534255. * distinguish between levels_lut and colors_lut this allows uint16 images with user lut to be rendered as Format_Indexed8 * uint8 (1-chan) images should always combine to efflut this efflut will then be used for Indexed8 format color table. previously, we would be taking a performance hit with doing a numpy lookup with levels_lut. * adapt benchmarks/makeARGB.py to renderImageItem.py * restructure uint8 and uint16 codepaths * normalize 1-chan images to ndim==2 earlier up * refactor long code into functions * bug: qimage may not be assigned * fix: assign to self.qimage only if not None * for uint16, do rescale rather than do levels_lut lookup * cases 2,3 are already handled i.e. no more using lut to do rescale of uint16 image data. * rescale rgb images by computation, not by memory lookup * setImage() does not take an output argument * try to be cupy compatible use "xp" instead of numpy module * add numba to benchmarking * fix: lut_big is dtype uint8 with more than 256 entries * bug: applying colors_lut needs C-order * support float with no nans * fix: variable could be uninitialized * add float32 format tests * avoid explicitly forcing to C-contiguous * cache effective lut only if combination took place every one of the four branches now does its own return. this makes it easier to follow. * fix cupy benchmark : typo in renderQImage * remove for loop of 1 iteration * use float32 for floating point benchmark * superceded by renderImageItem.py * lint * benchmark without lut conversion * put the lut onto the substrate * fix editor complaints * handle lack of cupy * leading underscores imply privacy Co-authored-by: KIU Shueng Chuan <nixchuan@gmail.com>
2021-05-20 00:21:12 +00:00
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
def check_format(shape, dtype, levels, lut, expected_format):
data = np.zeros(shape, dtype=dtype)
item = pg.ImageItem(axisOrder='row-major')
item.setImage(data, autoLevels=False, lut=lut, levels=levels)
item.render()
assert item.qimage.format() == expected_format
def test_uint8():
Format = QtGui.QImage.Format
dtype = np.uint8
w, h = 192, 108
lo, hi = 50, 200
lut_none = None
lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8)
lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8)
lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8)
lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8)
# lut with less than 256 entries
lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8)
lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8)
lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8)
lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8)
# lut with more than 256 entries
lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8)
lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8)
lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8)
lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8)
levels = None
check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale8)
check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888)
check_format((h, w, 4), dtype, levels, lut_none, Format.Format_RGBA8888)
levels = [lo, hi]
check_format((h, w), dtype, levels, lut_none, Format.Format_Indexed8)
levels = None
check_format((h, w), dtype, levels, lut_mono1, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba, Format.Format_Indexed8)
levels = [lo, hi]
check_format((h, w), dtype, levels, lut_mono1, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_l, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2_l, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb_l, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba_l, Format.Format_Indexed8)
levels = [lo, hi]
check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888)
def test_uint16():
Format = QtGui.QImage.Format
dtype = np.uint16
w, h = 192, 108
lo, hi = 100, 10000
lut_none = None
lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8)
lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8)
lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8)
lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8)
# lut with less than 256 entries
lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8)
lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8)
lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8)
lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8)
# lut with more than 256 entries
lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8)
lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8)
lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8)
lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8)
levels = None
try:
fmt_gray16 = Format.Format_Grayscale16
except AttributeError:
fmt_gray16 = Format.Format_ARGB32
check_format((h, w), dtype, levels, lut_none, fmt_gray16)
check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888)
check_format((h, w, 4), dtype, levels, lut_none, Format.Format_RGBA64)
levels = [lo, hi]
check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale8)
levels = None
check_format((h, w), dtype, levels, lut_mono1, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_l, Format.Format_Grayscale8)
check_format((h, w), dtype, levels, lut_mono2_l, Format.Format_Grayscale8)
check_format((h, w), dtype, levels, lut_rgb_l, Format.Format_RGBX8888)
check_format((h, w), dtype, levels, lut_rgba_l, Format.Format_RGBA8888)
levels = [lo, hi]
check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888)
def test_float32():
Format = QtGui.QImage.Format
dtype = np.float32
w, h = 192, 108
lo, hi = -1, 1
lut_none = None
lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8)
lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8)
lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8)
lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8)
# lut with less than 256 entries
lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8)
lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8)
lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8)
lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8)
# lut with more than 256 entries
lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8)
lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8)
lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8)
lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8)
levels = [lo, hi]
check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale8)
check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888)
check_format((h, w, 4), dtype, levels, lut_none, Format.Format_RGBA8888)
check_format((h, w), dtype, levels, lut_mono1, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono2_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgb_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_rgba_s, Format.Format_Indexed8)
check_format((h, w), dtype, levels, lut_mono1_l, Format.Format_Grayscale8)
check_format((h, w), dtype, levels, lut_mono2_l, Format.Format_Grayscale8)
check_format((h, w), dtype, levels, lut_rgb_l, Format.Format_RGBX8888)
check_format((h, w), dtype, levels, lut_rgba_l, Format.Format_RGBA8888)