Source code for pzp_hardware.generic.patterning.patterns

# This file is a part of pzp-hardware, a library of laboratory hardware support Pieces
# for the puzzlepiece GUI & automation framework. Check out https://pzp-hardware.readthedocs.io
# Licensed under the Apache License 2.0 - https://github.com/jdranczewski/pzp-hardware/blob/main/LICENSE

"""
:module_title:`Patterns`

Display a set of test patterns (circle, square, checkerboard) on any Piece with an array parameter
(DMD, SLM, etc).

Example usage (see :ref:`getting-started` for more details on using Pieces in general)::

    import puzzlepiece as pzp
    from pzp_hardware.vialux import dmd
    from pzp_hardware.generic.patterning import patterns

    app = pzp.QApp()
    puzzle = pzp.Puzzle(debug=False)
    puzzle.add_piece("dmd", dmd.Piece, row=0, column=0)
    puzzle.add_piece("patterns", patterns.Piece, row=0, column=1, param_defaults={
        "destination": "dmd:image"
    })
    puzzle.show()
    app.exec()
"""

import puzzlepiece as pzp
import numpy as np
from pyqtgraph.Qt import QtWidgets

[docs] class Piece(pzp.Piece): """ Piece for displaying test patterns. The "destination" param should be a string reference to an ArrayParam in the format ``piece_name:param_name``. The destination must already contain an image, so that its shape can be inspected. .. image:: ../images/pzp_hardware.generic.patterning.patterns.Piece.png """ def define_params(self): pzp.param.text(self, "destination", "dmd:image", visible=False)(None) pzp.param.spinbox(self, 'radius', 50, v_min=1)(None) pzp.param.slider( self, "brightness", 255, v_min=0, v_max=255, v_step=1, visible=False )(None) pzp.param.checkbox(self, 'invert', 0)(None) pzp.param.checkbox(self, 'stretch', 0, visible=False)(None).set_group("Stretch") pzp.param.spinbox( self, 'factor', 1., v_min=.1, v_max=10., v_step=.05, visible=False )(None).set_group("Stretch") def define_actions(self): @pzp.action.define(self, 'Display') def display(self): destination = pzp.parse.parse_params(self["destination"].value, self.puzzle)[0] radius = self.params['radius'].get_value() canvas = np.zeros(destination.value.shape, np.uint8) function = [x.dmd_draw_function for x in self._radio_buttons.buttons() if x.isChecked()][0] function(canvas, radius) if self.params['invert'].value: canvas = - (canvas - 255) canvas[canvas>0] = self["brightness"].value destination.set_value(canvas) pzp.action.settings(self) def custom_layout(self): layout = QtWidgets.QVBoxLayout() self._radio_buttons = QtWidgets.QButtonGroup() for i, f in enumerate((self.circle, self.square, self.checkerboard)): button = QtWidgets.QRadioButton(f.__name__) button.dmd_draw_function = f if not i: button.setChecked(True) button.clicked.connect(lambda _: self.actions['Display']()) layout.addWidget(button) self._radio_buttons.addButton(button) self.params['radius'].changed.connect(self.actions['Display']) self.params['brightness'].changed.connect(self.actions['Display']) self.params['invert'].changed.connect(self.actions['Display']) self.params['factor'].changed.connect(self.actions['Display']) # self.params['stretch'].changed.connect(self.actions['Display']) layout.addStretch() return layout def circle(self, canvas, radius): x, y = canvas.shape xx, yy = np.mgrid[:x, :y] factor = self["factor"].value if self["stretch"].value else 1 circle = np.sqrt(((xx - x/2) / factor)**2 + (yy - y/2)**2) canvas[circle <= radius] = 255 def square(self, canvas, radius): x, y = canvas.shape factor = self["factor"].value if self["stretch"].value else 1 A, B, C, D = x//2 - int(radius*factor), x//2 + int(radius*factor), y//2 - radius, y//2 + radius canvas[A:B, C:D] = 255 def checkerboard(self, canvas, radius): x, y = canvas.shape board = np.asarray([[0, 255], [255, 0]]) factor = self["factor"].value if self["stretch"].value else 1 board = np.kron(board, np.ones((int(radius*factor), radius))) canvas[:] = np.pad(board, ((0, x-2*int(radius*factor)), (0, y-2*radius)), mode='wrap')
if __name__ == "__main__": from puzzlepiece.extras import hardware_tools as pht app = pzp.QApp() puzzle = pzp.Puzzle(name="Patterns", debug=True) puzzle.add_piece("patterns", Piece, 0, 0) puzzle.show() app.exec()