Dependencies#

You can define dependencies between leaf features, allowing one parameter to influence another. For example, you may want larger leaves to have different color distributions than smaller leaves, or size and orientation to be correlated. Dependencies are specified when defining parameter distributions by replacing the parameter value with a dictionary defining the dependency:

    {"from": <value>, "fn": <callable>}

Sampling Order and Valid Dependencies#

Dependencies must respect the internal sampling order of the model:

  • Color can depend on geometry, but geometry cannot depend on color.

  • Shape parameters may depend on one another.

  • Cyclic dependencies are not allowed.

Defining Dependency Functions#

Single-Feature Dependencies#

If a parameter depends on a single feature, the value of "from" is that feature name, and the function fn receives a single value, returning the dependent parameter.

    {"from": "x_pos", "fn": lambda x: x * 0.01}

Example

Hide code cell source

from deadleaves import LeafGeometryGenerator, LeafAppearanceSampler, ImageRenderer

model = LeafGeometryGenerator(
    "circular", 
    {"area": {"powerlaw": {"low": 1000.0, "high": 10000.0, "k": 1.5}}},
    (512,512)
)
leaf_table, segmentation_map = model.generate_segmentation()

colormodel = LeafAppearanceSampler(leaf_table)
colormodel.sample_color(
    {
        "H": {"normal": {
            "loc": {"from": "x_pos", "fn": lambda x: 1/512*x * 0.3 + (1-1/512*x) * 0.6}, 
            "scale": 0.05
        }},
        "S": {"normal": {"loc": 0.6, "scale": 0.1}},
        "V": {"normal": {"loc": 0.6, "scale": 0.1}}
        }
)

renderer = ImageRenderer(colormodel.leaf_table, segmentation_map)
renderer.render_image()
renderer.show(figsize = (3,3))
../_images/4fccf9316aaac9bf36c7bf53b84b627477966a1119a3cf1e3ed31fd93315c12d.png

Multi-Feature Dependencies#

If a parameter depends on multiple features, "from" must be a list of feature names. In this case, fn receives a dictionary mapping feature names to their sampled values:

{
    "from": ["x_pos","y_pos"],
    "fn": lambda d: (d["x_pos"]**2 + d["y_pos"]**2)**0.5
}

This enables defining complex dependencies between spatial, geometric, and visual properties.

Example

Hide code cell source

from deadleaves import LeafGeometryGenerator, LeafAppearanceSampler, ImageRenderer
import torch

model = LeafGeometryGenerator(
    "circular", 
    {"area": {"powerlaw": {"low": 1000.0, "high": 10000.0, "k": 1.5}}},
    (512,512)
)
leaf_table, segmentation_map = model.generate_segmentation()

def fn(d):
    distance_from_center = torch.sqrt(torch.tensor((256 - d["x_pos"]) ** 2 + (256 - d["y_pos"]) ** 2))
    return torch.where(distance_from_center <= 128, 0.5, 0.8)

colormodel = LeafAppearanceSampler(leaf_table)
colormodel.sample_color(
    {
        "H": {"normal": {
            "loc": {"from": ["x_pos","y_pos"], "fn": fn}, 
            "scale": 0.05
        }},
        "S": {"normal": {"loc": 0.6, "scale": 0.1}},
        "V": {"normal": {"loc": 0.6, "scale": 0.1}}
        }
)

renderer = ImageRenderer(colormodel.leaf_table, segmentation_map)
renderer.render_image()
renderer.show(figsize = (3,3))
../_images/12770d94ee864122b3445b2ca4f89c4c68e9fb04d40753be47353cc5ab44cea1.png