Source code for QVideo.filters.rgb
'''RGB color-channel selection filter and companion Qt widget.'''
from qtpy import QtCore, QtWidgets
from QVideo.lib.QVideoFilter import VideoFilter, QVideoFilter
from QVideo.lib.videotypes import Image
__all__ = ['RGBFilter', 'QRGBFilter']
[docs]
class RGBFilter(VideoFilter):
'''Extracts a single color channel from an RGB image.
For grayscale (2-D) input the frame is passed through unchanged
regardless of the :attr:`channel` setting.
Parameters
----------
channel : int
Channel index to extract: ``0`` = Red, ``1`` = Green,
``2`` = Blue. Default: ``0``.
'''
def __init__(self, channel: int = 0) -> None:
super().__init__()
self.channel = channel
@property
def channel(self) -> int:
'''Channel index (0=Red, 1=Green, 2=Blue).'''
return self._channel
@channel.setter
def channel(self, channel: int) -> None:
if channel not in (0, 1, 2):
raise ValueError(f'channel must be 0, 1, or 2; got {channel}')
self._channel = channel
[docs]
def to_code(self) -> 'FilterCode':
from QVideo.lib.QVideoFilter import FilterCode
names = {0: 'Red', 1: 'Green', 2: 'Blue'}
ch = self._channel
return FilterCode(
imports=frozenset(),
lines=[
f'image = image[:, :, {ch}] if image.ndim == 3 else image # {names[ch]}',
],
comment=f'{names[ch]} channel',
)
[docs]
def add(self, image: Image) -> None:
'''Extract the selected channel and store the result.
Parameters
----------
image : Image
Input frame. 2-D arrays are stored unchanged; 3-D arrays
have the selected channel extracted.
'''
if image.ndim == 3:
self.data = image[:, :, self._channel]
else:
self.data = image
[docs]
class QRGBFilter(QVideoFilter):
'''Widget for :class:`RGBFilter` with Red/Green/Blue radio buttons.
Parameters
----------
parent : QtWidgets.QWidget or None
Parent widget.
'''
display_name = 'Color Channel'
display_category = 'Preprocessing'
def __init__(self, parent: QtWidgets.QWidget | None = None) -> None:
super().__init__(parent, 'Color Channel', RGBFilter())
def _setupUi(self) -> None:
super()._setupUi()
labels = ['Red', 'Green', 'Blue']
self._buttons = [QtWidgets.QRadioButton(t) for t in labels]
for n, button in enumerate(self._buttons):
button.toggled.connect(lambda checked, n=n:
self.setChannel(checked, n))
self._layout.addWidget(button)
self._buttons[self.filter.channel].setChecked(True)
[docs]
@QtCore.Slot(bool, int)
def setChannel(self, checked: bool, channel: int) -> None:
'''Set the active color channel.
Called on every radio button toggle; only acts when *checked*
is ``True`` to avoid updating the filter on the deselection
signal of the previous button.
Parameters
----------
checked : bool
Whether the button is being selected (``True``) or
deselected (``False``).
channel : int
Channel index corresponding to the toggled button.
'''
if checked:
self.filter.channel = channel
if __name__ == '__main__': # pragma: no cover
QRGBFilter.example()