Source code for cutcutcodec.core.generation.video.equation

"""Allow to generate colors from mathematical functions."""

import numbers
import re

from sympy.core.basic import Basic

from cutcutcodec.core.classes.container import ContainerInput
from cutcutcodec.core.filter.video.equation import FilterVideoEquation


[docs] class GeneratorVideoEquation(FilterVideoEquation, ContainerInput): """Generate a video stream whose channels are defened by any equations. It is a particular case of ``cutcutcodec.core.filter.equation.FilterVideoEquation``. Examples -------- >>> from cutcutcodec.core.generation.video.equation import GeneratorVideoEquation >>> (stream,) = GeneratorVideoEquation( ... "atan(pi*j)/pi + 1/2", # dark red on the left and bright on the right ... "sin(2pi(i-t))**2", # horizontal descending green waves ... "exp(-(i**2+j**2)/(2*(1e-3+.1*t)))", # blue spot in the center that grows ... ).out_streams >>> stream.node.colors [atan(pi*j)/pi + 1/2, sin(2*pi*(i - t))**2, exp((-i**2 - j**2)/((2*(0.1*t + 0.001))))] >>> stream.snapshot(0, (13, 9))[..., 0].round(decimals=3) # red at t=0 tensor([[0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020], [0.0980, 0.1280, 0.1800, 0.2880, 0.5000, 0.7120, 0.8200, 0.8720, 0.9020]]) >>> stream.snapshot(0, (13, 9))[..., 1].round(decimals=3) tensor([[0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500, 0.7500], [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]) >>> stream.snapshot(0, (13, 9))[..., 2].round(decimals=3) # red at t=0 tensor([[0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 1., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 0., 0.]]) >>> stream.snapshot(1, (13, 9))[..., 2].round(decimals=3) # red at t=1 tensor([[0.0000, 0.0000, 0.0020, 0.0050, 0.0070, 0.0050, 0.0020, 0.0000, 0.0000], [0.0000, 0.0020, 0.0090, 0.0240, 0.0320, 0.0240, 0.0090, 0.0020, 0.0000], [0.0010, 0.0070, 0.0320, 0.0810, 0.1110, 0.0810, 0.0320, 0.0070, 0.0010], [0.0020, 0.0180, 0.0840, 0.2130, 0.2900, 0.2130, 0.0840, 0.0180, 0.0020], [0.0040, 0.0360, 0.1670, 0.4230, 0.5770, 0.4230, 0.1670, 0.0360, 0.0040], [0.0060, 0.0540, 0.2530, 0.6400, 0.8720, 0.6400, 0.2530, 0.0540, 0.0060], [0.0070, 0.0620, 0.2900, 0.7340, 1.0000, 0.7340, 0.2900, 0.0620, 0.0070], [0.0060, 0.0540, 0.2530, 0.6400, 0.8720, 0.6400, 0.2530, 0.0540, 0.0060], [0.0040, 0.0360, 0.1670, 0.4230, 0.5770, 0.4230, 0.1670, 0.0360, 0.0040], [0.0020, 0.0180, 0.0840, 0.2130, 0.2900, 0.2130, 0.0840, 0.0180, 0.0020], [0.0010, 0.0070, 0.0320, 0.0810, 0.1110, 0.0810, 0.0320, 0.0070, 0.0010], [0.0000, 0.0020, 0.0090, 0.0240, 0.0320, 0.0240, 0.0090, 0.0020, 0.0000], [0.0000, 0.0000, 0.0020, 0.0050, 0.0070, 0.0050, 0.0020, 0.0000, 0.0000]]) >>> """ def __init__(self, *colors: Basic | numbers.Real | str): """Initialise and create the class. Parameters ---------- *colors : str or sympy.Basic Transmitted to the ``cutcutcodec.core.filter.video.equation.FilterVideoEquation`` initialisator. But the only available vars are `t`, `i` and `j`. """ FilterVideoEquation.__init__(self, [], *colors) ContainerInput.__init__(self, self.out_streams) if excess := ( {s for s in self._free_symbs if re.fullmatch(r"i|j|t", str(s)) is None} ): raise ValueError(f"only i, j, and t symbols are allowed, not {excess}")