class_docstr: Widget used for display and analysis of image data.
  Implements many features:
  
    * Displays 2D and 3D image data. For 3D data, a z-axis
      slider is displayed allowing the user to select which frame is displayed.
    * Displays histogram of image data with movable region defining the dark/light levels
    * Editable gradient provides a color lookup table
    * Frame slider may also be moved using left/right arrow keys as well as pgup, pgdn, home, and end.
    * Basic analysis features including:
  
        * ROI and embedded plot for measuring image values across frames
        * Image normalization / background subtraction
  
  Basic Usage::
  
      imv = pg.ImageView()
      imv.show()
      imv.setImage(data)
      
  **Keyboard interaction**
  
    * left/right arrows step forward/backward 1 frame when pressed,
      seek at 20fps when held.
    * up/down arrows seek at 100fps
    * pgup/pgdn seek at 1000fps
    * home/end seek immediately to the first/last frame
    * space begins playing frames. If time values (in seconds) are given
      for each frame, then playback is in realtime.
class_docstr_tok: ["Widget","used","for","display","and","analysis","of","image","data",".","Implements","many","features",":","*","Displays","2D","and","3D","image","data",".","For","3D","data",",","a","z-axis","slider","is","displayed","allowing","the","user","to","select","which","frame","is","displayed",".","*","Displays","histogram","of","image","data","with","movable","region","defining","the","dark\/light","levels","*","Editable","gradient","provides","a","color","lookup","table","*","Frame","slider","may","also","be","moved","using","left\/right","arrow","keys","as","well","as","pgup",",","pgdn",",","home",",","and","end",".","*","Basic","analysis","features","including",":","*","ROI","and","embedded","plot","for","measuring","image","values","across","frames","*","Image","normalization","\/","background","subtraction","Basic","Usage",":",":","imv","=","pg.ImageView","(",")","imv.show","(",")","imv.setImage","(","data",")","*","*","Keyboard","interaction","*","*","*","left\/right","arrows","step","forward\/backward","1","frame","when","pressed",",","seek","at","20fps","when","held",".","*","up\/down","arrows","seek","at","100fps","*","pgup\/pgdn","seek","at","1000fps","*","home\/end","seek","immediately","to","the","first\/last","frame","*","space","begins","playing","frames",".","If","time","values","(","in","seconds",")","are","given","for","each","frame",",","then","playback","is","in","realtime","."]
docstr: By default, this class creates an :class:`ImageItem <pyqtgraph.ImageItem>` to display image data
  and a :class:`ViewBox <pyqtgraph.ViewBox>` to contain the ImageItem.
  
  Parameters
  ----------
  parent : QWidget
      Specifies the parent widget to which this ImageView will belong. If None, then the ImageView is created with
      no parent.
  name : str
      The name used to register both the internal ViewBox and the PlotItem used to display ROI data. See the
      *name* argument to :func:`ViewBox.__init__() <pyqtgraph.ViewBox.__init__>`.
  view : ViewBox or PlotItem
      If specified, this will be used as the display area that contains the displayed image. Any
      :class:`ViewBox <pyqtgraph.ViewBox>`, :class:`PlotItem <pyqtgraph.PlotItem>`, or other compatible object is
      acceptable. Note: to display axis ticks inside the ImageView, instantiate it with a PlotItem instance as its
      view::
  
          pg.ImageView(view=pg.PlotItem())
  imageItem : ImageItem
      If specified, this object will be used to display the image. Must be an instance of ImageItem or other
      compatible object.
  levelMode : str
      See the *levelMode* argument to :func:`HistogramLUTItem.__init__() <pyqtgraph.HistogramLUTItem.__init__>`
  discreteTimeLine : bool
      Whether to snap to xvals / frame numbers when interacting with the timeline position.
  roi : ROI
      If specified, this object is used as ROI for the plot feature. Must be an instance of ROI.
  normRoi : ROI
      If specified, this object is used as ROI for the normalization feature. Must be an instance of ROI.
code: def __init__(
      self,
      parent=None,
      name="ImageView",
      view=None,
      imageItem=None,
      levelMode="mono",
      discreteTimeLine=False,
      roi=None,
      normRoi=None,
      *args,
  ):
      """
      By default, this class creates an :class:`ImageItem <pyqtgraph.ImageItem>` to display image data
      and a :class:`ViewBox <pyqtgraph.ViewBox>` to contain the ImageItem.
  
      Parameters
      ----------
      parent : QWidget
          Specifies the parent widget to which this ImageView will belong. If None, then the ImageView is created with
          no parent.
      name : str
          The name used to register both the internal ViewBox and the PlotItem used to display ROI data. See the
          *name* argument to :func:`ViewBox.__init__() <pyqtgraph.ViewBox.__init__>`.
      view : ViewBox or PlotItem
          If specified, this will be used as the display area that contains the displayed image. Any
          :class:`ViewBox <pyqtgraph.ViewBox>`, :class:`PlotItem <pyqtgraph.PlotItem>`, or other compatible object is
          acceptable. Note: to display axis ticks inside the ImageView, instantiate it with a PlotItem instance as its
          view::
  
              pg.ImageView(view=pg.PlotItem())
      imageItem : ImageItem
          If specified, this object will be used to display the image. Must be an instance of ImageItem or other
          compatible object.
      levelMode : str
          See the *levelMode* argument to :func:`HistogramLUTItem.__init__() <pyqtgraph.HistogramLUTItem.__init__>`
      discreteTimeLine : bool
          Whether to snap to xvals / frame numbers when interacting with the timeline position.
      roi : ROI
          If specified, this object is used as ROI for the plot feature. Must be an instance of ROI.
      normRoi : ROI
          If specified, this object is used as ROI for the normalization feature. Must be an instance of ROI.
      """
      QtWidgets.QWidget.__init__(self, parent, *args)
      self._imageLevels = (
          None  # [(min, max), ...] per channel image metrics
      )
      self.levelMin = None  # min / max levels across all channels
      self.levelMax = None
  
      self.name = name
      self.image = None
      self.axes = {}
      self.imageDisp = None
      self.ui = ui_template.Ui_Form()
      self.ui.setupUi(self)
      self.scene = self.ui.graphicsView.scene()
      self.discreteTimeLine = discreteTimeLine
      self.ui.histogram.setLevelMode(levelMode)
      self.ignoreTimeLine = False
  
      if view is None:
          self.view = ViewBox()
      else:
          self.view = view
      self.ui.graphicsView.setCentralItem(self.view)
      self.view.setAspectLocked(True)
      self.view.invertY()
  
      self.menu = None
  
      self.ui.normGroup.hide()
  
      if roi is None:
          self.roi = PlotROI(10)
      else:
          self.roi = roi
      self.roi.setZValue(20)
      self.view.addItem(self.roi)
      self.roi.hide()
      if normRoi is None:
          self.normRoi = PlotROI(10)
          self.normRoi.setPen("y")
      else:
          self.normRoi = normRoi
      self.normRoi.setZValue(20)
      self.view.addItem(self.normRoi)
      self.normRoi.hide()
      self.roiCurves = []
      self.timeLine = InfiniteLine(0, movable=True)
      if getConfigOption("background") == "w":
          self.timeLine.setPen((20, 80, 80, 200))
      else:
          self.timeLine.setPen((255, 255, 0, 200))
      self.timeLine.setZValue(1)
      self.ui.roiPlot.addItem(self.timeLine)
      self.ui.splitter.setSizes([self.height() - 35, 35])
  
      # init imageItem and histogram
      if imageItem is None:
          self.imageItem = ImageItem()
      else:
          self.imageItem = imageItem
          self.setImage(
              imageItem.image,
              autoRange=False,
              autoLevels=False,
              transform=imageItem.transform(),
          )
      self.view.addItem(self.imageItem)
      self.currentIndex = 0
  
      self.ui.histogram.setImageItem(self.imageItem)
      self.ui.histogram.setLevelMode(levelMode)
  
      # make splitter an unchangeable small grey line:
      s = self.ui.splitter
      s.handle(1).setEnabled(False)
      s.setStyleSheet("QSplitter::handle{background-color: grey}")
      s.setHandleWidth(2)
  
      self.ui.roiPlot.hideAxis("left")
      self.frameTicks = VTickGroup(yrange=[0.8, 1], pen=0.4)
      self.ui.roiPlot.addItem(self.frameTicks, ignoreBounds=True)
  
      self.keysPressed = {}
      self.playTimer = QtCore.QTimer()
      self.playRate = 0
      self._pausedPlayRate = None
      self.fps = 1  # 1 Hz by default
      self.lastPlayTime = 0
  
      self.normRgn = LinearRegionItem()
      self.normRgn.setZValue(0)
      self.ui.roiPlot.addItem(self.normRgn)
      self.normRgn.hide()
  
      ## wrap functions from view box
      for fn in ["addItem", "removeItem"]:
          setattr(self, fn, getattr(self.view, fn))
  
      ## wrap functions from histogram
      for fn in [
          "setHistogramRange",
          "autoHistogramRange",
          "getLookupTable",
          "getLevels",
      ]:
          setattr(self, fn, getattr(self.ui.histogram, fn))
  
      self.timeLine.sigPositionChanged.connect(self.timeLineChanged)
      self.ui.roiBtn.clicked.connect(self.roiClicked)
      self.roi.sigRegionChanged.connect(self.roiChanged)
      # self.ui.normBtn.toggled.connect(self.normToggled)
      self.ui.menuBtn.clicked.connect(self.menuClicked)
      self.ui.normDivideRadio.clicked.connect(self.normRadioChanged)
      self.ui.normSubtractRadio.clicked.connect(self.normRadioChanged)
      self.ui.normOffRadio.clicked.connect(self.normRadioChanged)
      self.ui.normROICheck.clicked.connect(self.updateNorm)
      self.ui.normFrameCheck.clicked.connect(self.updateNorm)
      self.ui.normTimeRangeCheck.clicked.connect(self.updateNorm)
      self.playTimer.timeout.connect(self.timeout)
  
      self.normProxy = SignalProxy(
          self.normRgn.sigRegionChanged,
          slot=self.updateNorm,
          threadSafe=False,
      )
      self.normRoi.sigRegionChangeFinished.connect(self.updateNorm)
  
      self.ui.roiPlot.registerPlot(self.name + "_ROI")
      self.view.register(self.name)
  
      self.noRepeatKeys = [
          QtCore.Qt.Key.Key_Right,
          QtCore.Qt.Key.Key_Left,
          QtCore.Qt.Key.Key_Up,
          QtCore.Qt.Key.Key_Down,
          QtCore.Qt.Key.Key_PageUp,
          QtCore.Qt.Key.Key_PageDown,
      ]
  
      self.roiClicked()
  
imports: import os
  from math import log10
  from time import perf_counter
  import numpy
  from ..None import debug
  from ..None import functions
  from ..None import getConfigOption
  from ..graphicsItems.GradientEditorItem import addGradientListToDocstring
  from ..graphicsItems.ImageItem import ImageItem
  from ..graphicsItems.InfiniteLine import InfiniteLine
  from ..graphicsItems.LinearRegionItem import LinearRegionItem
  from ..graphicsItems.ROI import ROI
  from ..graphicsItems.ViewBox import ViewBox
  from ..graphicsItems.VTickGroup import VTickGroup
  from ..Qt import QtCore, QtGui, QtWidgets
  from ..SignalProxy import SignalProxy
  from .None import ImageViewTemplate_generic
label_desc: Use image node_id 1 to create a new ImageView object from inherited base classes: QtWidgets with example: obj = ImageView(parent, name, view, imageItem, levelMode, discreteTimeLine, roi, normRoi)