Skip to content

ImageItem lut + levels combine is currently a pessimization #1590

@pijyoi

Description

@pijyoi

Short description

Intent of https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/graphicsItems/ImageItem.py#L419-L440 is to combine levels and lut such that apply levels is a no-op in the subsequent call to makeARGB()

Code to reproduce

import pyqtgraph as pg
import numpy as np
pg.setConfigOptions(imageAxisOrder='row-major')

app = pg.mkQApp()
imv = pg.ImageView()
imv.show()
data = np.random.randint(0, 256, size=(4096, 4096), dtype=np.uint8)
imv.setImage(data)
app.exec_()

Expected behavior

apply levels should take very little time in makeARGB() profiling

Real behavior

both apply levels and apply lut take significant time to execute

> Entering functions.makeARGB
  check inputs: 0.0219 ms
  apply levels: 374.5632 ms
  apply lut: 230.2356 ms
  allocate: 0.0088 ms
  reorder channels: 84.9686 ms
  alpha channel: 11.7705 ms
< Exiting functions.makeARGB, total time: 703.3772 ms

Tested environment(s)

  • PyQtGraph version: 0.11.1.dev0
  • Qt Python binding: PySide2 5.15.2 Qt 5.15.2
  • Python version: 3.7.9
  • NumPy version: 1.19.4
  • Operating system: Windows 10 x64
  • Installation method: pip install -e .

Additional context

As far can I understand, the intended behavior relied on code that was changed in #793.

For uint8 data,

The following lines rely on levels[1] == scale in order to bypass apply levels
https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/functions.py#L1182-L1183

So for instance, if #793 were reverted (just for the purpose of demonstration of this issue), we would get the following:
(i.e. apply levels is practically a no-op)

> Entering functions.makeARGB
  check inputs: 0.0324 ms
  apply levels: 0.0243 ms
  apply lut: 215.7016 ms
  allocate: 0.0088 ms
  reorder channels: 69.7846 ms
  alpha channel: 10.7770 ms
< Exiting functions.makeARGB, total time: 298.7649 ms

If, on the other hand, the lines performing the combination of lut and levels were commented out altogether, https://github.com/pyqtgraph/pyqtgraph/blob/master/pyqtgraph/graphicsItems/ImageItem.py#L422-L440
we would get an even better timing:
i.e. both lut=None and levels=None passed into makeARGB(), making both apply levels and apply lut no-ops

> Entering functions.makeARGB
  check inputs: 0.3414 ms
  apply levels: 0.0269 ms
  apply lut: 0.0055 ms
  allocate: 0.0036 ms
  reorder channels: 84.2574 ms
  alpha channel: 12.9225 ms
< Exiting functions.makeARGB, total time: 97.5745 ms

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceProblems or questions related to speed, efficiency, etc.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions