Controls Usage Examples

Setup

Initialize a new camera to get access to its controls:

from quarklib import Camera

cam = Camera()

Hierarchy navigation

The camera’s controls structure is a tree structure, with nodes closer to the top representing larger groups of controls. Here’s an example of some of the root nodes your camera may contain:

  • controls.digital_gain: Digital gain for RGB colors.

  • controls.flip: Horizontal/vertical image flipping.

  • controls.color_conversion: Color correction controls. Contains further levels of controls for the color matrix components.

All controls are either leaves and correspond to an actual V4L2 control or they are branches and define a group of controls. Each group has its children defined as attributes, i.e. for a given a group control group_a, its child leaf_1 can be accessed using group_a.leaf_1. Below are a few examples based on the real controls presented above:

print(cam.digital_gain.red) # Prints info about the specified control
print(cam.digital_gain.green)

print(cam.color_conversion.ccm)

Basic reading/writing

Each control (both groups and leaves) have a read() and a write(val) methods.

print(cam.digital_gain.red.read())
cam.digital_gain.red.write(3.5)
cam.digital_gain.red.write(4.5) # raises ValueError because the value is outside the allowed range

cam.color_conversion.ccm.offset.write(np.array([0.2, 0.5, 0.2, 0.5]))
cam.pattern_generator.write("gradation") # set the generated pattern
cam.pattern_generator.write("invalid") # also raises a ValueError

Control metadata

Each control has a formatter property which returns either a single AbstractFormatter (for leaf controls) or a dict[str, AbstractFormatter | dict] (for group controls). The formatter objects provide information on the control’s value limits. They are used internally when reading/writing controls to convert to/from the raw format used in V4L2 and the format used by the user (e.g. floats that are represented as fixed point numbers on the camera).

# Red gain - a Q2.14 fixed point number.
fmt = cam.controls.digital_gain.red.formatter
print(fmt) # prints some basic information.
print(fmt.valid_set) # get the valid values, described as an interval of (min, max, step).
# validate the provided value. For floats, the validation only checks if the value is
# within the min and max value and simply rounds to the nearest representable value.
print(fmt.validate_value(1.5))
print(fmt.clamp_value) # Fully clamp the value to the allowed interval.

# Pattern generator - a menu value.
fmt2 = cam.controls.pattern_generator
print(fmt2.valid_set) # prints the list of possible menu values.
fmt2.validate_value("sequence 2") # succeeds only if the value matches exactly one valid value.
fmt2.clamp_value("seq 2") # Finds the closest match. Might be good for user input.

Grouped reading/writing

All controls that represent arrays can be manipulated using the indexing syntax provided by NumPy. Not that this still reads/writes the whole value (as required by V4L2) but it still means that the library user won’t have to worry about storing temporary values.

Certain group controls, those that represent arrays that are shape-compatible, also provide an indexing syntax that allows reading/writing across multiple V4L2 controls using a single read/write.

These concepts are best demonstrated with examples:

# Write the identity matrix to the top-left part of the ccm matrix:
# The actual control is 4x4 but the indexing only writes to a
# 3x3 corner.
cam.controls.color_conversion.ccm.matrix[:3, :3] = np.eye(3)

# Groups that contain numeric children with shapes that can be stacked,
# also supports this indexing operation.

# Here we get the red and green values for the digital_gain control group:
cam.controls.digital_gain[:2]

# The CCM consists of two matrices, forming an affine transformation when combined.
# It can be accessed like so:
cam.controls.color_conversion.ccm[0, :] = np.ones((5,))

# Indexing over the full range of values is equivalent to calling read/write, i.e., the
# following operations are pairwise equivalent:

# These both read all values
x = cam.controls.color_conversion.ccm.read()
x = cam.controls.color_conversion.ccm[:,:]

# These both write all values
cam.controls.color_conversion.ccm.write(x)
cam.controls.color_conversion.ccm[:,:] = x