Controls Usage Examples ======================= Setup ----- Initialize a new camera to get access to its controls: .. code-block:: python 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: .. code-block:: python 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. .. code-block:: python 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). .. code-block:: python # 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: .. code-block:: python # 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