Shapes#
The shape of the objects in a Dead Leaves image are specified via the leaf_shapeargument of the LeafGeometryGenerator.
Currently support shapes are:
circularellipsoidrectangularpolygon
Shape-specific parameters are passed through the shape_param_distributionsdictionary.
The required parameters depend on the chosen shape.
Note
For comparability all shape sizes are parameterized via an area parameter, which describes the distribution of the leaves size in terms of number of pixels (i.e. squared pixels).
Circles#
Circular leaves (leaf_shape = "circular") are the simplest, requiring only the area or radius distribution:
{
"area": <distribution>
}
or
{
"radius": <distribution>
}
The leaf mask for a circular leaf with position \((\bar{x},\bar{y})\) and area \(A\) or radius \(r\) is then generated via
Tip
To generate images with powerlaw distributed leaf radius (for a \(1/f\) power spectrum) simply use a powerlaw distributed area with exponent k.
For parameterization via the area the value of k should be half of what you would use for the radius to achieve the same distribution.
Example
Ellipsoids#
Ellipsoidal leaves (leaf_shape = "ellipsoid") require distributions for
area: size of the ellipseaspect_ratio: ratio of minor to major axisorientation: rotation angle.
{
"area": <distribution>,
"orientation": <distribution>,
"aspect_ratio": <distribution>
}
The leaf mask for a ellipsoidal leaf with position \((\bar{x},\bar{y})\), area \(A\), aspect ratio \(\rho\), and orientation \(\phi\) is then generated via
Example
Rectangles#
Rectangular leaves (leaf_shape = "rectangular") use the same parameters as ellipsoids:
{
"area": <distribution>,
"orientation": <distribution>,
"aspect_ratio": <distribution>
}
The leaf mask for a rectangular leaf with position \((\bar{x},\bar{y})\), area \(A\), aspect ratio \(R\), and orientation \(\phi\) is then generated via
Example
Regular polygons#
Currently only regular polygons with fixed orientation are supported (leaf_shape = "polygon").
The parameters are area and number of vertices n_vertices:
{
"area": <distribution>,
"n_vertices": <distribution>
}
The leaf mask for a regular polygon leaf with position \((\bar{x},\bar{y})\), area \(A\), and number of vertices \(n\) is then generated by computing the positions of the vertices via
We then use a simple Ray-casting algorithm to check if a pixel \((x,y)\) is with in the convex hull of the vertices, i.e. the polygon.
Example
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
Cell In[4], line 11
7 "n_vertices": {"poisson": {"rate": 5}},
8 },
9 (256, 256)
10 )
---> 11 leaf_table, segmentation_map = model.generate_segmentation()
12
13 colormodel = LeafAppearanceSampler(leaf_table)
14 colormodel.sample_color({"gray": {"uniform": {"low": 0.0, "high": 1.0}}})
File ~/checkouts/readthedocs.org/user_builds/deadleaves/checkouts/latest/deadleaves/deadleaves.py:335, in LeafGeometryGenerator.generate_segmentation(self)
332 continue
334 # Compute AABB, clip to canvas, query live tiles
--> 335 y_min, x_min, y_max, x_max = leaf_mask_kw[self.leaf_shape].bbox(
336 params
337 ) # pyright: ignore[reportCallIssue]
338 y_min = max(y_min, 0)
339 x_min = max(x_min, 0)
File ~/checkouts/readthedocs.org/user_builds/deadleaves/checkouts/latest/deadleaves/leaf_masks.py:304, in leaf_aabb(params, leaf_shape)
302 area = float(params["area"])
303 n_v = int(params["n_vertices"])
--> 304 r = math.sqrt(2 * area / (n_v * math.sin(2 * math.pi / n_v)))
305 return (
306 math.floor(cy - r),
307 math.floor(cx - r),
308 math.ceil(cy + r),
309 math.ceil(cx + r),
310 )
312 # Fallback — unknown shape, return infinite box (no acceleration)
ValueError: math domain error