Module redvox.api1000.gui.image_viewer

Provides a basic image gallery for API M image sensors.

Expand source code
"""
Provides a basic image gallery for API M image sensors.
"""

try:
    import sys
    import datetime
    from typing import Optional, TYPE_CHECKING

    import numpy as np
    # pylint: disable=E0611
    from PySide6.QtCore import Qt, QByteArray
    # pylint: disable=E0611
    from PySide6.QtGui import QPixmap
    # pylint: disable=E0611
    from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QLabel, QTableWidget, QTableWidgetItem, \
        QHeaderView, QSizePolicy, QAbstractItemView

    import redvox

    if TYPE_CHECKING:
        from redvox.api1000.wrapped_redvox_packet.sensors.image import Image


    class ImageSelectionWidget(QTableWidget):
        """
        This widget provides a table view of available images in the packet.
        """

        def __init__(self,
                     image_sensor: 'Image',
                     image_view_widget: 'ImageViewWidget',
                     parent: Optional[QWidget] = None) -> None:
            super().__init__(image_sensor.get_num_images(), 2, parent=parent)

            self.setSelectionBehavior(QAbstractItemView.SelectRows)
            self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            self.resizeColumnsToContents()

            extension: str = image_sensor.get_file_ext()
            timestamps: np.ndarray = image_sensor.get_timestamps().get_timestamps()

            self.setHorizontalHeaderLabels(["File Name", "Image Sampled At"])
            for (i, timestamp) in enumerate(timestamps):
                name: str = f"{round(timestamp)}.{extension}"
                date_time: datetime.datetime = datetime.datetime.utcfromtimestamp(timestamp / 1_000_000.0)
                self.setItem(i, 0, QTableWidgetItem(name))
                self.setItem(i, 1, QTableWidgetItem(str(date_time)))

            def __update_image_at_row(row: int) -> None:
                buf: bytes = image_sensor.get_samples()[row]
                image_view_widget.set_image(buf)

            self.currentCellChanged.connect(__update_image_at_row)


    class ImageViewWidget(QLabel):
        """
        This widget displays and scales the image
        """

        def __init__(self, _: Optional[QWidget] = None) -> None:
            super().__init__(parent=None)
            self.setAlignment(Qt.AlignCenter)

        def set_image(self, buf: bytes) -> None:
            """
            Sets the image.
            :param buf: Image bytes to set
            """
            pix: QPixmap = QPixmap()
            pix.loadFromData(QByteArray(buf))
            self.setPixmap(pix.scaled(self.width(),
                                      self.height(),
                                      Qt.AspectRatioMode.KeepAspectRatio,
                                      Qt.TransformationMode.SmoothTransformation))


    class ImageViewer(QWidget):
        """
        Widget that acts as the "main" widget into the application
        """

        def __init__(self, image_sensor: 'Image', parent: Optional[QWidget] = None) -> None:
            super().__init__(parent)
            self.setLayout(QHBoxLayout(self))

            image_view_widget: ImageViewWidget = ImageViewWidget()
            image_selection_widget: ImageSelectionWidget = ImageSelectionWidget(image_sensor, image_view_widget)
            size_policy: QSizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
            size_policy.setHorizontalStretch(1)
            image_selection_widget.setSizePolicy(size_policy)
            self.layout().addWidget(image_selection_widget)

            size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
            size_policy.setHorizontalStretch(2)
            image_view_widget.setSizePolicy(size_policy)
            self.layout().addWidget(image_view_widget)


    class MainWindow(QMainWindow):
        """
        Main window of the application
        """

        def __init__(self, image_sensor: 'Image', parent: Optional[QWidget] = None) -> None:
            super().__init__(parent)
            self.setWindowTitle(f"RedVox Image Viewer v{redvox.VERSION}")
            self.setCentralWidget(ImageViewer(image_sensor, self))


    def start_gui(image_sensor: 'Image') -> None:
        """
        Starts the GUI from the provided image sensor.
        :param image_sensor: Image sensor
        """
        app: QApplication = QApplication(sys.argv)
        window: MainWindow = MainWindow(image_sensor)
        window.showMaximized()
        app.exec_()

except ImportError:
    import warnings
    warnings.warn("GUI dependencies are not installed. Install the 'GUI' extra to enable this functionality.")

Functions

def start_gui(image_sensor: Image)

Starts the GUI from the provided image sensor. :param image_sensor: Image sensor

Expand source code
def start_gui(image_sensor: 'Image') -> None:
    """
    Starts the GUI from the provided image sensor.
    :param image_sensor: Image sensor
    """
    app: QApplication = QApplication(sys.argv)
    window: MainWindow = MainWindow(image_sensor)
    window.showMaximized()
    app.exec_()

Classes

class ImageSelectionWidget (image_sensor: Image, image_view_widget: ImageViewWidget, parent: Optional[PySide6.QtWidgets.QWidget] = None)

QTableWidget(self, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None QTableWidget(self, rows: int, columns: int, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None

init(self, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None init(self, rows: int, columns: int, parent: Optional[PySide6.QtWidgets.QWidget] = None) -> None

Initialize self. See help(type(self)) for accurate signature.

Expand source code
class ImageSelectionWidget(QTableWidget):
    """
    This widget provides a table view of available images in the packet.
    """

    def __init__(self,
                 image_sensor: 'Image',
                 image_view_widget: 'ImageViewWidget',
                 parent: Optional[QWidget] = None) -> None:
        super().__init__(image_sensor.get_num_images(), 2, parent=parent)

        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.resizeColumnsToContents()

        extension: str = image_sensor.get_file_ext()
        timestamps: np.ndarray = image_sensor.get_timestamps().get_timestamps()

        self.setHorizontalHeaderLabels(["File Name", "Image Sampled At"])
        for (i, timestamp) in enumerate(timestamps):
            name: str = f"{round(timestamp)}.{extension}"
            date_time: datetime.datetime = datetime.datetime.utcfromtimestamp(timestamp / 1_000_000.0)
            self.setItem(i, 0, QTableWidgetItem(name))
            self.setItem(i, 1, QTableWidgetItem(str(date_time)))

        def __update_image_at_row(row: int) -> None:
            buf: bytes = image_sensor.get_samples()[row]
            image_view_widget.set_image(buf)

        self.currentCellChanged.connect(__update_image_at_row)

Ancestors

  • PySide6.QtWidgets.QTableWidget
  • PySide6.QtWidgets.QTableView
  • PySide6.QtWidgets.QAbstractItemView
  • PySide6.QtWidgets.QAbstractScrollArea
  • PySide6.QtWidgets.QFrame
  • PySide6.QtWidgets.QWidget
  • PySide6.QtCore.QObject
  • PySide6.QtGui.QPaintDevice
  • Shiboken.Object

Class variables

var staticMetaObject
class ImageViewWidget

QLabel(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None QLabel(self, text: str, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

init(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None init(self, text: str, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

Initialize self. See help(type(self)) for accurate signature.

Expand source code
class ImageViewWidget(QLabel):
    """
    This widget displays and scales the image
    """

    def __init__(self, _: Optional[QWidget] = None) -> None:
        super().__init__(parent=None)
        self.setAlignment(Qt.AlignCenter)

    def set_image(self, buf: bytes) -> None:
        """
        Sets the image.
        :param buf: Image bytes to set
        """
        pix: QPixmap = QPixmap()
        pix.loadFromData(QByteArray(buf))
        self.setPixmap(pix.scaled(self.width(),
                                  self.height(),
                                  Qt.AspectRatioMode.KeepAspectRatio,
                                  Qt.TransformationMode.SmoothTransformation))

Ancestors

  • PySide6.QtWidgets.QLabel
  • PySide6.QtWidgets.QFrame
  • PySide6.QtWidgets.QWidget
  • PySide6.QtCore.QObject
  • PySide6.QtGui.QPaintDevice
  • Shiboken.Object

Class variables

var staticMetaObject

Methods

def set_image(self, buf: bytes) ‑> None

Sets the image. :param buf: Image bytes to set

Expand source code
def set_image(self, buf: bytes) -> None:
    """
    Sets the image.
    :param buf: Image bytes to set
    """
    pix: QPixmap = QPixmap()
    pix.loadFromData(QByteArray(buf))
    self.setPixmap(pix.scaled(self.width(),
                              self.height(),
                              Qt.AspectRatioMode.KeepAspectRatio,
                              Qt.TransformationMode.SmoothTransformation))
class ImageViewer (image_sensor: Image, parent: Optional[PySide6.QtWidgets.QWidget] = None)

QWidget(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

init(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, f: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

Initialize self. See help(type(self)) for accurate signature.

Expand source code
class ImageViewer(QWidget):
    """
    Widget that acts as the "main" widget into the application
    """

    def __init__(self, image_sensor: 'Image', parent: Optional[QWidget] = None) -> None:
        super().__init__(parent)
        self.setLayout(QHBoxLayout(self))

        image_view_widget: ImageViewWidget = ImageViewWidget()
        image_selection_widget: ImageSelectionWidget = ImageSelectionWidget(image_sensor, image_view_widget)
        size_policy: QSizePolicy = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
        size_policy.setHorizontalStretch(1)
        image_selection_widget.setSizePolicy(size_policy)
        self.layout().addWidget(image_selection_widget)

        size_policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        size_policy.setHorizontalStretch(2)
        image_view_widget.setSizePolicy(size_policy)
        self.layout().addWidget(image_view_widget)

Ancestors

  • PySide6.QtWidgets.QWidget
  • PySide6.QtCore.QObject
  • PySide6.QtGui.QPaintDevice
  • Shiboken.Object

Class variables

var staticMetaObject
class MainWindow (image_sensor: Image, parent: Optional[PySide6.QtWidgets.QWidget] = None)

QMainWindow(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, flags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

init(self, parent: Optional[PySide6.QtWidgets.QWidget] = None, flags: PySide6.QtCore.Qt.WindowType = Default(Qt.WindowFlags)) -> None

Initialize self. See help(type(self)) for accurate signature.

Expand source code
class MainWindow(QMainWindow):
    """
    Main window of the application
    """

    def __init__(self, image_sensor: 'Image', parent: Optional[QWidget] = None) -> None:
        super().__init__(parent)
        self.setWindowTitle(f"RedVox Image Viewer v{redvox.VERSION}")
        self.setCentralWidget(ImageViewer(image_sensor, self))

Ancestors

  • PySide6.QtWidgets.QMainWindow
  • PySide6.QtWidgets.QWidget
  • PySide6.QtCore.QObject
  • PySide6.QtGui.QPaintDevice
  • Shiboken.Object

Class variables

var staticMetaObject