Source code for ovl.visions.multi_vision

import numpy as np
from typing import Union, List, Any, Generator, Tuple, Dict

from ..helpers.types import VisionLike
from .ambient_vision import AmbientVision
from ..connections.connection import *
from ..connections.network_location import NetworkLocation


[docs]class MultiVision: """ An object used to switch between multiple vision objects. It does this by having a list of visions and a connection and network_location to update from So it can be automatically updated to swap to the desired Vision object use the start method to start an infinite loop that returns images and detections .. code-block:: python connection = ovl.NetworkTablesConnection(1937) vision1 = ovl.Vision(....) vision2 = ovl.Vision(....) vision3 = ovl.Vision(....) update_location = ovl.NetworkLocation(table_key="current_vision") multi_vision = ovl.MultiVision([vision1, vision2, vision3], connection, update_location) for directions, contours, image in multi_vision.start(): # do something with the generated data # like sending the data or displaying the contours multi_vision.send(directions) ovl.display_contours(image, contours, delay=1) """ def __init__(self, visions: Union[List[VisionLike], Dict[Any, VisionLike]], update_connection: Connection, update_location: Union[NetworkLocation, None] = None, default_vision=0): self.current = visions[default_vision] self.index = default_vision self.visions = visions self.connection = update_connection self.update_location = update_location self.switch_functions = {list: self._list_switch_vision, dict: self._dict_switch_vision} def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.connection.close()
[docs] def is_ambient(self) -> bool: """ Returns True if the current_vision vision is an Ambient vision object :return: if the current vision is an AmbientVision """ return isinstance(self.current, AmbientVision)
[docs] def send(self, data, *args, **kwargs) -> Any: """ Sends the value to the target destination of the current_vision vision object :param data: the data to be sent :return: depends on the connection object """ return self.current.send(data=data, *args, **kwargs)
[docs] def set_vision(self, index): """ Sets the current to the given index :param index: the index to set :return: the index """ self.current = self.visions[self.index] self.index = index return index
def _dict_switch_vision(self, index: int): """ Switches the current vision to the one given if the visions container is a list """ return index in self.visions def _list_switch_vision(self, index: Any): """ Switches the current vision to the one given if the visions container is a dictionary """ return 0 <= index < len(self.visions)
[docs] def switch_vision(self, index: Any): """ Switches the current vision used to the vision at the given index (can be a key for dictionaries) :param index: the index of the new vision, can be an int if the container of the visions is a list or any immutable object if it is a dictionary :return: the index set (the index given if it is valid and """ if self.switch_functions[type(self.visions)](index): self.set_vision(index) return index return self.index
[docs] def update_current(self) -> int: """ Reads the updated current vision from the update network location and then updates the current vision :return: the index received """ new_idx = self.connection.receive_from_location(network_location=self.update_location or {}) self.switch_vision(new_idx) return new_idx
[docs] def start(self, yield_ratios=False) -> Generator[Tuple[List[np.ndarray], np.ndarray, Any], None, None]: """ A function that starts an infinite generator that takes an image detects with the current vision and returns the list of contours the image and directions and should be used as follows: .. code-block:: python connection = ovl.NetworkTablesConnection(1937) vision1 = ovl.Vision(....) vision2 = ovl.Vision(....) vision3 = ovl.Vision(....) update_location = ovl.NetworkLocation(table_key="current_vision") multi_vision = ovl.MultiVision([vision1, vision2, vision3], connection, update_location) for directions, contours, image in multi_vision.start(): # do something with the generated data # like sending the data or displaying the contours multi_vision.send(directions) ovl.display_contours(image, contours, delay=1) Note: automatically updates AmbientVision's vision swapping (AmbientVision.update_vision())! :param yield_ratios: if True also yields the list of ratios returned from :yields: contours image directions and ratios if yield_ratios if True """ while True: self.update_current() image = self.current.get_image() contours, filtered_image = self.current.detect(image, return_ratios=yield_ratios) directions = self.current.director.direct(contours, filter, self.current.camera_settings) if self.is_ambient(): self.current.update_vision() yield directions, contours, filtered_image